我决定把资源倒腾倒腾发上来,一方面分享大致思路,另一方面也当是纪念了
做的是2020电赛F题:简易无接触温度测量与身份识别装置

文章目录

  • 题目
  • 整体设计
    • 硬件选择
    • 软件流程
  • 视觉算法
    • 分辨不同人脸(身份识别)
    • 口罩识别
    • 现场学习
    • 其他优化算法
  • 资源与总结

题目

整体设计

硬件选择

机器视觉模块使用openmv,这一方面是我们在备赛过程中认为openmv的功能足够,一直在准备openmv,另一方面是当时马上下单k210开始学习等到货都已经第三天了,调试来不及风险太大了,所以决定使用openmv
好在我们买的是最顶配型号openmvH7Plus,最终也顺利完成了题目要求的所有任务

温度测量方面是MLX90614使用某宝的模块i2c读取温度,最终我们没有省一拿了省二也是砸在这个模块上,在送测现场出了问题,血的教训,万事都要做好plan B啊~~
主控使用stm32c8t6,这是因为我们在赛前已经用顺手了,其他的也行
其他硬件包括oled显示温度阈值等,按键,有源蜂鸣器,激光小灯等就不赘述了
最后的电路板设计,器件布局如下

软件流程

stm32和openmv通过串口通信,我们指定一个字母对应进入一个模式,通电后openmv就在死循环不断等待字母,收到字母即执行对应模式功能,再返回结果。具体可看软件流程图:

视觉算法

由于分工上我主要负责openmv视觉部分的代码编写等部分,所以这里多说几句视觉方面的python代码编写的心路历程

刚开始学习阶段主要参考的资料就是心疼科技的两个函数库链接:
https://book.openmv.cc/
https://docs.singtown.com/micropython/zh/latest/openmvcam/library/index.html
b站视频也有看点

分辨不同人脸(身份识别)

拿到题目第一反应就是中文入门教程里面看到过这个LBP分辨不同人脸的应用,于是我第一天也确确实实按照手册的思路拍照测试了,但是实际效果并不好,而且受光线和背景影响很大,脸还必须填满摄像头,就很不方便
于是后来又发现了特征点算法,运算时间有了很大提升,但还有一个问题就是如果背景拍到的范围过大,那么将会从背景提取很多无用的特征点,而要求人保持一定的距离把人脸填满屏幕实在太蠢了,怎么解决呢?
我的方法是先加一层人脸识别,将人脸部分局部放大截取出来再拿去提取特征点并进行特征点比对,通过这种方法,就不用对被识别者有很大的要求,实现类似k210一样的功能啦~
关于上面这个思路,直接上代码:

#画出特征点
def draw_keypoints(img, kpts):if kpts:print(kpts)img.draw_keypoints(kpts)img = sensor.snapshot()time.sleep(1000)def find_max(pmax, a, s):global face_numif a>pmax:pmax=aface_num=sreturn pmaxdef Distinguish_faces():global NUM_SUBJECTSglobal NUM_SUBJECTS_IMGSpyb.LED(3).on()# 重置传感器sensor.reset()sensor.set_contrast(3)sensor.set_gainceiling(16)sensor.set_framesize(sensor.VGA)sensor.set_windowing((240, 240))#sensor.set_framesize(sensor.B128X128) # or sensor.QQVGA (or others)sensor.set_pixformat(sensor.GRAYSCALE)#set_auto_gain :enable 打开(True)或关闭(False)自动增益。默认打开。 value 强迫增益值。#sensor.set_auto_gain(False, value=1000)#sensor.set_auto_gain(False, gain_db =700)sensor.set_auto_gain(True, gain_db_ceiling = 20.0)sensor.skip_frames(time = 500)pmax=0#保存检测点和样本点的匹配程度,越大越接近,初始化为最小loop_flag=1#循环检测标志位,检测到人脸身边识别后退出type_flag=0#kpts1类别正确标志位,正确为1,错误为0while(loop_flag):#加了histeq子自适应直方图均衡,当人脸填满整个屏幕的时候可以提高一点点识别准确度.histeq(adaptive=True, clip_limit=3)#找图片中人脸#gamma_corr用于修正图像中色彩,数值越高图像越亮faces = sensor.snapshot().gamma_corr(contrast=1.5).find_features(image.HaarCascade("frontalface"))lcd.display(sensor.snapshot())#lcd.display(sensor.snapshot())#打印增益值#print("Gain %f dB, Exposure %d us" % \#    (sensor.get_gain_db(), sensor.get_exposure_us()))if faces:#获取image中人像部分largest_face的roilargest_face = max(faces, key = lambda f: f[3] * f[3])img=sensor.get_fb().crop(roi=largest_face)#裁剪人脸部分保存到imgkpts1=img.find_keypoints(max_keypoints=90, threshold=0, scale_factor=1.3)#注意,这里就是之前bug的位置,因为找到截取出的人脸图片,因为距离和光线原因,可能找不到特征点#此时kpts1会返回nonetype,所以必须这边判断一致才能进入特征点比对#print(type(kpts1).__name__=='kp_desc')#.__name__直接返回数据类型#print((type(kpts1)=="<class 'kptmatch'>")==0)#python两字符串比较==若相等返回0if(type(kpts1).__name__=='kp_desc'):#kpts1的类型是kp_desc,也就是确保find_keypoints找到了特征点type_flag=1else:print("kpts1 type wrong")type_flag=0else:print("find no face")#仅当图片中有人脸(正脸)且裁切脸部分找到了特征点,才进行特征点比对判断if type_flag:loop_flag=0lcd.display(img)#print(type(kpts1))#print(isinstance(kpts1,Kptmatch))#img.draw_keypoints(kpts)#画出此时的目标特征,没有调用那个定义的函数draw_keypoints(img, kpts1)num=0#下面进行特征点比对kpts2=None#存储每个人的特征值feature_values=[0]#这里赋值0只是为了初始化一个列表,在后面求方差计算的时候把列表长度减一即可,0加for s in range(1, NUM_SUBJECTS+1):match_count = int(0)angle_count=0for i in range(2, NUM_SUBJECTS_IMGS+1):kpts2=image.load_descriptor("/keypoints/s%s/%s.orb"%(s,i))#匹配当前找到的特征和最初的目标特征的相似度# #threshold阈值设置匹配的准确度,用来过滤掉有歧义的匹配。这个值越小,准确度越高。阈值范围0~100,默认70#filter_outliers默认关闭。#对于ORB描述符来说,这个函数返回的是kptmatch对象。#print(image.match_descriptor(kpts1, kpts2).count())#res=image.match_descriptor(kpts1, kpts2)match_count+=image.match_descriptor(kpts1, kpts2).count()#angle_count+=image.match_descriptor(kpts1, kpts2).theta()#print("Average match_count for subject %d: %d"%(s, match_count/NUM_SUBJECTS_IMGS))print("Average match_count for subject %d: %d"%(s, match_count))#pmax = find_max(pmax, match_count/NUM_SUBJECTS_IMGS, s)#match_count越大,被检测人脸与此样本更相似更匹配。pmax = find_max(pmax, match_count, s)#print("pmax:%d"%pmax)feature_values.append(match_count)#存储每个人的特征值#计算平均值feature_sum=0for feature_value in feature_values:print("feature_value is %d" % feature_value)n=len(feature_values)-1feature_sum+=feature_valueaverage=feature_sum/nprint("average is %d" % average)print("n is %d" % n)#计算方差 (feature_value-average)的平方累加除npow_sum=0#方差计算式中的分子for feature_value in feature_values:#这一句将列表的第一个元素置为平均值,消除其对方差值的影响if feature_value==0:feature_value=averageprint("此项方差为%d" % math.pow(feature_value-average,2))pow_sum+=math.pow(feature_value-average,2)variance=pow_sum/nprint("variance is %d" % variance)#根据方差判断,如果三个人的结果差别很大则方差很大,相对来说结果可信,若差别不大则结果不可信if variance<1500:#和三个人都差距都较大,返回0#考虑写成当最大值和最小值的差值和平均值的差值差多少,则判断问不符合,#或者方差大则低阈值,方差小则高阈值uart.write(str(0))print("unknown person !") # face_num保存s中当前最匹配的人的编号。else:uart.write(str(face_num))#发送只能是字符,而不能是数字,所以需要格式转换str(b)print("The most similar person is:%d"%face_num) # face_num保存s中当前最匹配的人的编号。lcd.clear()pyb.LED(3).off()

当然代码中还有许多其他的小细节,比如最后加了一个方差计算,这是为了使得识别陌生人脸更准确,即如果拍摄特征点与内存中存储的三个人的特征点比对结果都差不多,也就是方差小,那就就很有可能并不是三个人中的一个人,而是陌生人,这个方差阈值是经过实践得出的,根据光线可能需要不同调整。

总结一下(速成版本,系统学习理论请参考其他大佬):

  • LBP局部二值模式:采集一定数量的模板 pgm 图片数据。在进行人脸识别时,将读取到的图片与模板数据库进行相似度比较,从中选取最高相似度的模板,从而确定被测人信息。
  • 特征点AGAST 算法(Adaptive and Generic Accelerated Segment Test):多尺度快速角点特征提取算法 步骤:提前保存目标特征 orb 文 件,在进行人脸识别时,提取目标的特征点与特征点库进行匹配得出结果,经过方差计算判断可信度后得出结果。

口罩识别

两种模型引申出的两种不同方法:(openmv算力不足情况下有已经很不错了)

  • 第一种是用haar算子,将xml类型的文件转为cascade格式,然后识别,详见使用openmv实现识别任意物体
    用 opencv 级 联 分 类 器 opencv_createsamples.exe 训练并生成.xml 文件,而后将其转换为.cascade 文件,生成口罩检测模型并导入 openmv 中,调用find_features进行识别判断。 其缺点是少量样本(几百个)训练的口罩模型在识别过程中准确度较低,且极易受环境噪 音影响,而大量样本(几万个)样本的训练需要长达几个月的结果才能得到较为精确的模型

  • 第二种是比赛到最后一天才发现有模型的,使用内置的tflite神经网络框架运行即可。现在openmv手册已经有了哈哈哈,估计是受到了电赛影响吧:https://book.openmv.cc/project/mask.html
    tflite(TensorFlow Lite)是谷歌推出的用于移动设备和 IoT 设备端推断的开源深度学习框架。 在 openmv4 plus 上具备了 2m 闪存和固件级支持的 tf 库,可以对捕捉图片进行脱机的神经 网络运算识别,且市面已具有相对成熟的口罩人脸 tflite 库,相比自己训练口罩模型,识别结果大幅提高

现场学习

由于使用特征点,现场学习不过就是把拍摄,提取特征点,文件保存放到现场进行罢了,在我这套逻辑下现场学习并没有多出多少难度,我们现场拍摄20张够够的了

#特征学习
def machine_learning():sensor.reset()sensor.set_contrast(3)sensor.set_gainceiling(16)sensor.set_framesize(sensor.VGA)sensor.set_windowing((240, 240))sensor.set_pixformat(sensor.GRAYSCALE)#sensor.set_auto_gain(True, value=0)sensor.set_auto_gain(True, gain_db_ceiling = 20.0)sensor.skip_frames(time = 2000)#set_auto_gain :enable 打开(True)或关闭(False)自动增益。默认打开。 value 强迫增益值。global NUM_SUBJECTS_IMGSglobal NUM_SUBJECTSprint("last NUM_SUBJECTS =%d" % NUM_SUBJECTS)NUM_SUBJECTS=NUM_SUBJECTS+1print("now NUM_SUBJECTS =%d" % NUM_SUBJECTS)p_num=NUM_SUBJECTS_IMGSs=NUM_SUBJECTSkpts1 = None#n=20while(p_num):#红灯亮pyb.LED(1).on()faces = sensor.snapshot().gamma_corr(contrast=1.5).find_features(image.HaarCascade("frontalface"))lcd.display(sensor.snapshot())lcd.clear()if faces:largest_face = max(faces, key = lambda f: f[3] * f[3])#获取image中人像部分roiimg=sensor.get_fb().crop(roi=largest_face)#裁剪lcd.display(img)#寻找保存整个图片中的特征点,因此要求拍摄内容尽量都是脸,上面进行图片中脸部的局部放大后提取特征点kpts1 = img.find_keypoints(max_keypoints=90, threshold=0, scale_factor=1.3)if (kpts1 == None):#图片中没有找到特征点#raise(Exception("Couldn't find any keypoints!"))print("Couldn't find any keypoints!")else:#画出此时的目标特征,没有调用那个定义的函数#img.draw_keypoints(kpts)draw_keypoints(img, kpts1)lcd.display(img)#保存此时图片和对应特征点orb文件#保存截取到的图片到SD卡,蓝灯亮的时候完成一次拍照image.save_descriptor(kpts1, "keypoints/s%s/%s.orb"%(s,p_num))img.save("keypoints/s%s/%s.pgm"%(s,p_num))p_num-=1print(p_num)#存一次亮一下提示#红灯灭,蓝灯亮pyb.LED(1).off()pyb.LED(3).on()sensor.skip_frames(time = 50)pyb.LED(3).off()uart.write(str(9))else:print("find no face")#学习完成闪两次绿灯pyb.LED(2).on()sensor.skip_frames(time = 100)pyb.LED(2).off()sensor.skip_frames(time = 100)pyb.LED(2).on()sensor.skip_frames(time = 100)pyb.LED(2).off()lcd.clear()uart.write(str("f"))#发送f代表学习完成

其他优化算法

为了让openmv能获得好的结果真的很努力呢哈哈哈

  • 直方图均值化:.histeq(adaptive=True, clip_limit=3) 直方图均值化后,灰度直方图几乎覆盖了整个灰度的取值范围,并且除了个别灰度值的个数较为突出,整个灰度值分布近似于均匀分布,经过这样处理的图像将具有较大的灰度动态范围和较高的对比度,图像的细节更为丰富。
  • 局部放大后识别:上面身边识别说过了。sensor.get_fb().crop(roi=largest_face)首先利用固件库自带人脸haar模型进行识别人脸,识别后截取人脸部分再进行特征点比对,这将提高精确度并减少运算量。
  • 自动增益:sensor.snapshot().gamma_corr(contrast=1.5)伽马校正用于修正图像中色彩和对比度,数值越高图像越亮

总的来说那两天是把micropython函数库翻了一遍,能试的都一个个试过去了,这几个是对结果确实有帮助的函数

资源与总结

我们最终获得了福建省二等奖,由于送测的时候90614模块出了问题,测温爆炸,反而其他部分包括视觉部分都是满分,遗憾没有省一,就当吸取要准备planB的教训了害。
关于openmv部分代码,主要内容都在上面一段一段都po出来了,口罩识别见链接官方有,以上都写出了要点,足够有能力的同学可以复现。
如果关于这个题目还有其他问题,也欢迎私信或email:949761064@qq.com
欢迎学习讨论,遇到问题的解决和互相交流分享经验,不支持直接索要硬件和软件工程代码!!直接索要代码不会回复哦!!请好好学习!
end

2020电赛F题总结回顾(openmv实现视觉)相关推荐

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

    2020电赛F题回顾--简易无接触温度测量与身份识别装置 第一次参加电赛,已经大三了,这也有可能是我的最后一次,不禁感慨时间过得真快.在实验室一起奋斗的夜晚既辛苦又幸福,感谢陪伴在我身边一起做电赛的同 ...

  2. python利用tensorflow识别圆_RaspberryPi上实现佩戴口罩识别——2020电赛F题小记

    今年的电赛题目非常反常,传统控制题目基本没有,新增加了测距题目,甚至物联网题目,Ai题目都出来了.直接电赛变算法+钞能力大赛.看到F题:测温+人脸识别,碰巧我们手头有调好的红外测温模块+树莓派+ope ...

  3. 2021电赛F题视觉教程+代码免费开源

    2021电赛F题视觉教程+代码免费开源 最近好多要电赛题的源码,其他csdn营销号下载都需要会员或钱,正好最近课设又要做一遍电赛小车题,哥们先把代码开源了,饿死营销号 电赛宝藏链接: 四天三夜,那布满 ...

  4. 2021电赛F题(智能送药小车)参赛总结【视觉部分】

    2021电赛F题(智能送药小车)参赛总结[视觉部分] 前言 在2021年全国大学生电子设计竞赛中,我们小组做的是F题(智能送药小车).我在小组中主要负责小车视觉功能的实现,所以在本篇参赛总结中只会涉及 ...

  5. 2021电赛F题-智能送药小车-国一

    2021电赛F题-智能送药小车-国一 B站视频链接:https://www.bilibili.com/video/BV1u44y1e7qk/ (这大概是b站第一个双车视频吧,嘿嘿

  6. 2021电赛F题智能送药小车方案分析(openMV数字识别,红线循迹,STM32HAL库freeRTOS,串级PID快速学习,小车自动返回)

    2021全国大学生电子设计竞赛F题智能送药小车 前提:本篇文章重在分享自己的心得与感悟,我们把最重要的部分,摄像头循迹,摄像头数字识别问题都解决了,有两种方案一种是openARTmini摄像头进行数字 ...

  7. 2022电赛F题思路

    2022电赛到现在为止已经出了结果.这是我第一次参加电赛,以前也没有相关的比赛经历,在这四天三夜的时间里能够和队友完成这样一项完整的作品,对我们来说都具有很大的意义.虽然最后还是有一些细节上的问题,不 ...

  8. 通过FPGA实现2022电赛F题

    这是本人第一次参加电赛,非常有收获,虽然电赛已经结束,不过并不影响把我的思路整理出来和大家交流一下,同时也为自己做个笔记,这里简单介绍一下思路,就不讲解程序了. 这次电赛的题目如下: 1.  设计思路 ...

  9. 2021电赛F题之openmv巡线(附代码)

    效果展示: 出错解决方法 openmv数字识别源代码–gitee 通过使用不同阈值的方法可以得到当前区域中什么区域有红线,对于电控而言作用类似于红外对管,之后电控通过逻辑判断如何运动,这就是我们队伍目 ...

  10. 视觉识别数字、十字路口和T字路口,巡线于一体的基于openmv的解决方案(2021年电赛f题)

    普通二本生(大二)没获奖,因为驱动方面和视觉协同问题没有做好(驱动方面跑太快,速度降不下来)只跑了最初级的,这个文章就是去记录一下我的成长过程吧. 目录 1.使用神经网络来进行识别 2.使用模板匹配来 ...

最新文章

  1. pandas版本_Datawhale十二月Pandas组学习打卡Task00.准备工作
  2. 十三、前端基本功:DOM练习
  3. 如何用python进行相关性分析_如何在python中检查连续变量和分类变量之间的相关性?...
  4. cheatengine找不到数值_“不会找问题”,只配在底层,最高效的思维方式导图,人生开挂!...
  5. linux删除第二次出现的字符,linux下 怎样删除文件名中包含特殊字符的文件
  6. Java数据结构--HashTable(拉链法)
  7. 赠书 | 隐私计算:让你的数据信息不再“裸奔”
  8. indexOf、lastIndexOf、substring等详解
  9. c++测试cpu_测评丨NXP系列 LS1028 LS1046等产品网络性能测试
  10. python 列表 移除_python:列表中多元素的删除(移除)
  11. JS设计模式初识(四)-迭代器模式
  12. Flume 知识点总结
  13. 使用STAR构建参考基因组并比对
  14. mui.ajax ie8,IE8+MVVM的适配方案尝试
  15. 模集经典二级运放设计
  16. android教师评价系统源码,教师评价系统
  17. excel 打开文件后自动卡死的解决方法
  18. wifi连接上不能上网怎么办服务器无响应,​wifi连接上不能上网是怎么回事,看完你就恍然大悟了...
  19. hive打patch流程说明
  20. 弱网测试学习记录(1)

热门文章

  1. FAT32、NTFS、exFAT的区别
  2. mastercam9.1按alt键卡机,mastercam输入参数卡机需要win10输入法兼容性设置
  3. 计算机无线网怎么安装教程,安装无线网必看 给家庭安装无线宽带WIFI的详细步骤(图)...
  4. 全职专业玩家分享:手动党梦幻五开赚钱心得
  5. 3D打印:三维智能数字化创造(全彩)
  6. 检察院批准逮捕洪磊,铁杆分子不买帐
  7. 【人工智能】AI竞赛,到底有什么价值?
  8. LearnOpenGL从入门到入魔(3):绘制纹理
  9. 纸笔骑士2 android,荐游:一张纸笔就是一次中二冒险的开始!《骑士经理》评测...
  10. 2.某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精设定⦁蛇怪类:属性包括:怪物名字,生命值,攻击力方法包括:攻击,移动(曲线移动),补血(当生命值<10时,可以补加20生命值