OpenMV(五)--STM32实现人脸识别_stm32人脸识别-程序员宅基地

技术标签: •OpenMV  stm32  •嵌入式AI  嵌入式硬件  单片机  

OpenMV(一)–基础介绍与硬件架构
OpenMV(二)–IDE安装与固件下载
OpenMV(三)–实时获取摄像头图片
OpenMV(四)–STM32实现特征检测

前言

本专栏基于以STM32H743为MCU的OpenMV-H7基板,结合OV7725卷帘快门摄像头进行相关机器视觉应用的开发。人脸识别的前提是人脸检测,本篇博文基于OpenMV官方的Face-Detection例程,来解析一下怎么实现人脸识别。

1. 人脸检测

人脸检测就是通过摄像头实时获取的图片,来标记出人脸的位置。本节代码的目的就是将摄像头拍摄的画面中的人脸用矩形框表示出来。人脸检测的本质是特征识别,OpenMV中已经集成了非常多的特征库和算法库,比如image模块下的find_features()特征寻找函数。

1.1 构造函数
  • image.find_features(cascade, threshold=0.5, scale=1.5, roi)
    搜索和Haar Cascade匹配的所有区域的图像,并返回一个关于这些特征的边界框矩形元祖(x, ,y, w, h)的列表,若没有发现任何特征,则返回一个空白列表。基于Haar特征的cascade分类器一种有效的物品检测(object detect)方法。它是一种机器学习方法,通过许多正负样例中训练得到cascade方程,然后将其应用于其他图片。详细内容可以参考博客:使用Haar Cascade 进行人脸识别
    • cascade:Haar Cascade 对象
    • threshold: 是浮点数(0.0-1.0),其中较小的值在提高检测速率同时增加误报率。相反,较高的值会降低检测速率,同时降低误报率。
    • scale: 是一个必须大于1.0的浮点数。较高的比例因子运行更快,但是其图像匹配相应较差。理想值介于1.35到1.5之间。
    • roi:指定识别区域的矩形元组(x, y, w, h)。如果没有指定,roi即整个图像的图像矩形。
1.2 源码分析
"""
人脸检测例程
利用Haar Cascade特征检测器来实现:一个Haar Cascade是一系列简单区域的对比检查,人脸识别有25个阶段,每个阶段有几百次检测。Haar Cascade运行很快是因为它是逐个阶段进行检测的。
OpenMV使用一种称为积分图像的数据结构来在恒定时间内快速执行每个区域的对比度检查
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置相机图像的对比度为1
sensor.set_contrast(1)

# 设置相机的增益上限为16
sensor.set_gainceiling(16)

# 设置采集到照片的大小
sensor.set_framesize(sensor.HQVGA)

# 设置采集到照片的格式:灰色图像
sensor.set_pixformat(sensor.GRAYSCALE)

# 加载Haar Cascade 模型
# 默认使用25个步骤,减少步骤会加快速度但会影响识别成功率
face_cascade = image.HaarCascade("frontalface", stage = 25)
print(face_cascade)

# 创建一个时钟来计算摄像头每秒采集的帧数FPS
clock = time.clock()

while(True):
	# 更新FPS时钟
	clock.tick()
	
	# 拍摄图片并返回img
	img = sensor.snapshot()

	# 寻找人脸对象
	# threshold和scale_factor两个参数控制着识别的速度和准确性
	objects = img.find_features(face_cascade, threshold=0.75, scale_factor=1.25)

	# 用矩形将人脸画出来
	for r in objects:
		img.draw_rectangle(r)
	
	# 串口打印FPS参数
	print(clock.fps())

我们将板子连接到OpenMV IDE, 新建文件,并将上述代码copy进去,点击左下角的绿色按钮,我们就可以看到IDE右边的窗口在实时显示提取到的人脸特征图片:
在这里插入图片描述

2. 人脸识别

人脸识别是通过短时间的人脸特征学习,再重新识别的过程,这节内容是基于第一小节的人脸检测的基础上完成的。

2.1 构造函数

本节是人脸检测和特征点识别的结合,实验用到的函数和对象在之前都有介绍过,分别是

  • image.find_features(cascade, threshold=0.5, scale=1.5, roi)
    收获和Haar Cascade 匹配的所有区域的对象,并返回关于这个特征的边界框矩形元组
  • image.find_keypoints(roi, threshold=20, normalize=False, scale_factor=1.5, max_keypoints=100, corner_detector=image.CORNER_AGAST)
    特征点识别函数,返回一个image.rect矩形对象列表
  • image.match_descriptor(descriptor0, descriptor1, threshold=70, filter_outliers=False)
    特征点对比函数。
2.2 源码分析

对于人脸识别,具体的实现步骤如下:
初始化和配置相应模块–>加载人脸检测Haar Cascade模型–>对当前的人脸学习并记录特征点K1–>在采集的图像中提取特征点K2–>对比K1和K2是否一致–>如果一致就在图中用矩形画出相应位置

"""
人脸识别例程
第一步先使用Haar Cascade找出人脸并记录该关键点
第二步就是不停的检测当前获取图片的关键点是否匹配
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置相机图像的对比度为3
sensor.set_contrast(3)

# 设置相机的增益上限为16
sensor.set_gainceiling(16)

# 设置采集到照片的大小
sensor.set_framesize(sensor.VGA)

# 在VGA(640*480)下开个小窗口,相当于数码缩放
sensor.set_windowing((320, 240))

# 设置采集到照片的格式:灰色图像
sensor.set_pixformat(sensor.GRAYSCALE)

# 加载Haar Cascade 模型
# 默认使用25个步骤,减少步骤会加快速度但会影响识别成功率
face_cascade = image.HaarCascade("frontalface", stage = 25)
print(face_cascade)

# 初始化特征kpts1
kpts1 = None

# 找到人脸
while(kpts1 == None):
	# 拍摄图片并返回img
	img = sensor.snapshot()
	img.draw_string(0, 0, "Looking for a face...")

	# 寻找人脸对象
	# threshold和scale_factor两个参数控制着识别的速度和准确性
	objects = img.find_features(face_cascade, threshold=0.5, scale_factor=1.25)
	
	if objects:
		# 将 ROI(x, y, w, h)往各个方向扩展31像素
		face = (objects[0][0]-31,
				objects[0][1]-31,
				objects[0][2]+31*2,
				objects[0][3]+31*2)
		# 使用扩展后的ROI区域(人脸)学习关键点
		kpts1 = img.find_keypoints(threshold = 10,
								   scale_factor = 1.1,
								   max_keypoints = 100,
								   roi = face)
		img.draw_keypoints(kpts1, size=24)
		img = sensor.snapshot()
		time.sleep(2000)

while(True):
	img = sensor.snapshot()
	# 从图像中提取关键点
	kpts2 = img.find_keypoints(threshold = 10,
							   scale_factor = 1.1,
							   max_keypoints = 100,
							   normalized = True)
	if(kpts2):
		# 跟kpts1匹配
		c = image.match_descriptor(kpts1, kpts2, threshold = 85)
		# c[6]为match值,值越大表示匹配程度越高
		match = c[6]
		if(match > 5):
			img.draw_rectangle(c[2:6])
			img.draw_cross(c[0], c[1], size = 10)

我们将板子连接到OpenMV IDE, 新建文件,并将上述代码copy进去,点击左下角的绿色按钮,我们就可以看到IDE右边的窗口在首先学习了人脸特征:
在这里插入图片描述
然后我们换一张还是吴彦祖的人脸看看是否能够进行识别:
在这里插入图片描述
从图中可以发现,已经成功识别了这张人脸特征。

3.通过本地特征文件进行人脸识别

第2节的例程是在线学习特征然后进行人脸识别,但是绝大多数的应用场景需要我们对比本地的人脸特征库和目标图像。我们要做的步骤有两部,首先要将人脸特征保存到本地,其次是调用本地的特征来进行人脸识别,下面我们将通过实例来分析如果实现这两个步骤。

3.1 将人脸特征保存到本地

将人脸特征保存到本地只需要一句语句即可:

 image.save_descriptor(kpts, "path")

其中kpts为要保存的特征点,path为保存路径。
源码如下:

"""
保存人脸特征例程
第一步先使用Haar Cascade识别出人脸,并获取人脸的特征
第二步就是将特征保存在本地文件中
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置相机图像的对比度为3
sensor.set_contrast(3)

# 设置相机的增益上限为16
sensor.set_gainceiling(16)

# 设置采集到照片的大小
sensor.set_framesize(sensor.VGA)

# 在VGA(640*480)下开个小窗口,相当于数码缩放
sensor.set_windowing((320, 240))

# 设置采集到照片的格式:灰色图像
sensor.set_pixformat(sensor.GRAYSCALE)

sensor.skip_frames(time = 3000)     # Wait for settings take effect.

# 加载Haar Cascade 模型
# 默认使用25个步骤,减少步骤会加快速度但会影响识别成功率
face_cascade = image.HaarCascade("frontalface", stage = 25)

# 初始化特征kpts1
kpts1 = None

# 文件名
FILE_NAME = "kpts1"
# 找到人脸
while(kpts1 == None):
    # 拍摄图片并返回img
    img = sensor.snapshot()
    img.draw_string(0, 0, "Looking for a face...")

    # 寻找人脸对象
    # threshold和scale_factor两个参数控制着识别的速度和准确性
    objects = img.find_features(face_cascade, threshold=0.5, scale_factor=1.25)

    if objects:
        # 将 ROI(x, y, w, h)往各个方向扩展31像素
        face = (objects[0][0]-31,
                objects[0][1]-31,
                objects[0][2]+31*2,
                objects[0][3]+31*2)
        # 使用扩展后的ROI区域(人脸)学习关键点
        kpts1 = img.find_keypoints(threshold = 10,
                                   scale_factor = 1.1,
                                   max_keypoints = 100,
                                   roi = face)
        img.draw_keypoints(kpts1, size=24)
        img = sensor.snapshot()
        #将人脸保存打本地文件
        image.save_descriptor(kpts1, "/face_feature/%s.orb"%(FILE_NAME))
3.2 通过本地特征文件进行人脸识别

提取本地特征文件只需要一句语句即可:

 kpts1 = image.load_descriptor("path")

其中kpts1为要本地文件中的特征,path为保存路径。
源码如下:

"""
加载本地特征文件进行人脸识别例程
第一步先从本地加载特征文件
第二步就是不停的检测当前获取图片的关键点判断是否和本地特征匹配
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置相机图像的对比度为3
sensor.set_contrast(3)

# 设置相机的增益上限为16
sensor.set_gainceiling(16)

# 设置采集到照片的大小
sensor.set_framesize(sensor.VGA)

# 在VGA(640*480)下开个小窗口,相当于数码缩放
sensor.set_windowing((320, 240))

# 设置采集到照片的格式:灰色图像
sensor.set_pixformat(sensor.GRAYSCALE)

sensor.skip_frames(time = 10000)     # Wait for settings take effect.

# 加载Haar Cascade 模型
# 默认使用25个步骤,减少步骤会加快速度但会影响识别成功率
face_cascade = image.HaarCascade("frontalface", stage = 25)
print(face_cascade)

# 从本地提取特征
kpts1 = image.load_descriptor("/face_feature/kpts1.orb")

while(True):
    img = sensor.snapshot()
    # 从图像中提取关键点
    kpts2 = img.find_keypoints(threshold = 10,
                               scale_factor = 1.1,
                               max_keypoints = 100,
                               normalized = True)
    if(kpts2):
        # 跟kpts1匹配
        c = image.match_descriptor(kpts1, kpts2, threshold = 85)
        # c[6]为match值,值越大表示匹配程度越高
        match = c[6]
        if(match > 10):
            img.draw_rectangle(c[2:6])
            img.draw_cross(c[0], c[1], color = (255,0,0), size = 10)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42580947/article/details/105861162

智能推荐

C语言中关于while语句的理解以及getchar和putchar_include<stdio.h>int main(){while(putchar(getchar()-程序员宅基地

文章浏览阅读888次,点赞32次,收藏9次。continue:跳过本次continue循环后面的代码,重新去判断部分(也就是重新进入while循环),看是否能够进行下一次循环。这串代码与上一次相比,我们把while中的条件改为了i_includeint main(){while(putchar(getchar())!='?'); return 0;}

74hc164驱动数码管c语言程序,74hc164应用电路图_74hc164驱动源程序-程序员宅基地

文章浏览阅读3.3k次。74hc164是高速硅门 CMOS 器件,与低功耗肖特基型 TTL (LSTTL) 器件的引脚兼容。74hc164是 8 位边沿触发式移位寄存器,串行输入数据,然后并行输出。数据通过两个输入端(DSA 或 DSB)之一串行输入;任一输入端可以用作高电平使能端,控制另一输入端的数据输入。两个输入端或者连接在一起,或者把不用的输入端接高电平,一定不要悬空。时钟 (CP) 每次由低变高时,数据右移一位,..._74hc164数码管

pyinstaller centos 打包记录_centos pyinstall-程序员宅基地

文章浏览阅读178次。报错2:error while loading shared libraries: libpython3.7m.so.1.0: cannot open shared object file: No such。报错1:OSError: Python library not found: libpython3.7mu.so.1.0, libpython3.7.so, l。添加库的配置信息,将python/lib的绝对路径(一般为:’/usr/python/lib’),添加至conf文件中。_centos pyinstall

linux下统计log中某个时间段的内出现某个关键字保存到文件_linux命令统计某个时间区间出现的关键字-程序员宅基地

文章浏览阅读674次。1、查看图中两个时间段内,且有“统计存储图片数据”的字段的日志 sed -n '/2021-06-03 11::25:34/,/2021-06-03 11:26:02/p' start.log |grep "统计存储图片数据" 注释: -n参数:只有经过sed特殊处理的那一行(或者动作)才会被显示 p参数:表示在终端打印出来 start.log:日志文件 grep: 对前面查询的结果进行过滤 "统计存储图片数据": 查询的关键字 时间段:格式和日志保持一致,且时间值是真实存在的2、将时._linux命令统计某个时间区间出现的关键字

手机翻译html工具,1分钟教你用手机实时翻译,自带翻译功能就是强大,各牌手机均可...-程序员宅基地

文章浏览阅读2.6k次。手机现在已经是我们的随身物品了,在很多事情上手机都可以帮助到我们,比如翻译,现在不仅是出国会用到翻译,就想平时的自我学习和工作上,都会遇到翻译的情况,今天就教大家一招用手机直接翻译的方法!今天主要就是给大家揭秘不同品牌手机里的翻译功能,一起来看看吧!1.小米手机小米手机在国产手机里的是非常受欢迎的,小米手机里的【扫一扫】不知道大家用过没有,我们打开扫一扫点击【翻译】然后选择翻译前后的语言,最后点击..._html格式的网页进行翻译

CSS背景background详解,background-position详解-程序员宅基地

文章浏览阅读3.3w次,点赞65次,收藏287次。背景(background)是css中一个重要的的部分,也是需要知道的css的基础知识之一。这篇文章将会涉及css背景(background)的基本用法,包括诸如 background-attachment 等的属性,也会介绍一些有关背景(background)的常用技巧,以及 css3 中的 背景(background)(包含4个新的背景(background)属性)。css2 中的背景(background)概述CSS2 中有5个主要的背景(background)属性,它们是:* ba_background-position

随便推点

使用Ajax实现简单的增删查改&&前端Ajax传的值,后端如何获取_ajax增删改查-程序员宅基地

文章浏览阅读4k次,点赞3次,收藏40次。实现查询和增删改一、Ajax最基本语法二、增删查改1.查询(Get请求)2.增删改(Post请求)三、后台(MVC/WebForm)1.MVC(Post请求)2.WebForm(Post请求)本人小白一个。其中所说可能有些不足,因为这些是我自己在写项目的过程中所使用的Ajax如有不对的地方,欢迎评论提出建议。一、Ajax最基本语法话不多说,直接上代码$.ajax({ url: "/User/GetUser",(这里写请求路径) type: "g_ajax增删改查

m4s格式转换mp4怎么转?只需3个步骤~-程序员宅基地

文章浏览阅读894次,点赞8次,收藏6次。无论您使用的是Windows、Mac还是Linux系统,主流播放器如VLC、Windows Media Player、QuickTime等都能轻松打开MP4文件,确保用户能够在各种平台上畅快观影。如果需要将M4S转换成MP4,野葱视频转换器为我们提供了便捷的解决方案,不仅具有稳定性,极少发生文件损坏,而且转换速度快,大大节约了时间。随着网络视频的普及,M4S通过分片存储音频和视频数据,提高了网络传输的效率,使得用户在观看视频时能够更加流畅地体验。处理完成后,你将在指定的输出路径中找到生成的MP4文件。_m4s格式转换mp4

CAN协议_为什么can诊断都是7开头-程序员宅基地

文章浏览阅读596次。网络管理报文(CAN 4开头,CAN FD 5开头),应用报文,诊断报文(7开头,物理寻址:一对一 比如对单体安全访问,在线编程,功能寻址:服务需要一对多,保证ECU的状态相同,比如多个 ECU需要知道车速的信息,温度的信息)CAN_H的电平为3.5V,CAN_L线的电平为1.5V,CAN_H和CAN_L的电压差为2V左右,CAN_H和CAN_L线上的电压均为2.5v, CAN_H和CAN_L之间的电压差为0V。1、位错误:当总线赢得发送权后,会对总线电平进行侦听,当发送的电平和侦听的电平不一致;_为什么can诊断都是7开头

基于OPC自定义接口的OPCClient功能改进_titaniumas.opc.client-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏9次。在本人之前的一篇博文中描写了如何使用OPC自定义接口开发OPCClient,并使用SignalR实现数据的远程实时传输。融合SignalR的OPCClient实现环境参数实时监测但是在使用过程中发现仍有不足之处,本文就是对之前OPCClient的功能改进进行说明。1.问题描述原有的OPCClient在测试环境下可以正常运行,但是在实际生产环境下长时间运行后问题就逐渐暴露出来。主要的问..._titaniumas.opc.client

宏工科技十五周年,“归零心态”竞逐全球-程序员宅基地

文章浏览阅读75次。宏工科技十五周年,“归零心态”竞逐全球

c++中的extern “C“_c++ extern c-程序员宅基地

文章浏览阅读1.6k次。c++中的extern "C"_c++ extern c

推荐文章

热门文章

相关标签