×

使用MTCNN和用于ESP32-S3的TensorFlow Lite进行人脸检测

消耗积分:0 | 格式:zip | 大小:0.00 MB | 2023-06-13

ejlwj

分享资料个

描述

介绍

前段时间我第一次听到“嵌入式机器学习”这个词,直到那时我才想到人工智能模型可以在微控制器上运行。一段时间后,我开始使用 TensorFlow 学习计算机视觉课程,然后图像处理背后的神秘主义以及创建和部署 AI 模型所需的所有过程对我来说变得清晰起来。这个项目是我对嵌入式系统的热情和这些新获得的知识的结果。前段时间我第一次听到“嵌入式机器学习”这个词,直到那时我才想到人工智能模型可以在微控制器上运行。一段时间后,我开始使用 TensorFlow 学习计算机视觉课程,然后图像处理背后的神秘主义以及创建和实施 AI 模型所需的所有过程对我来说变得清晰起来。在计算机视觉领域,我一直觉得很有趣的一个应用是面部检测,在该领域中,MTCNN 非常适合实施。这个项目是我对嵌入式系统的热情和这些新获得的知识的结果。

为什么?

它是如何工作的?

MTCNN(多任务级联卷积网络)是作为人脸检测和人脸对齐解决方案而开发的框架。它由三个阶段的卷积网络组成,能够识别人脸和标志性位置,例如眼睛、鼻子和嘴巴。

P-Net(提案网络)

这是一个FCN(Fully Convolutional Network),用于获取候选窗口及其边界框回归向量。当目标是检测某个预定义类的对象时,边界框回归是一种预测框定位的流行技术。获得的候选窗口用边界框回归向量进行校准,并用 NMS(非最大抑制)算子进行处理以组合重叠区域。

poYBAGSBN0yAFebIAABngXA4wtA582.png
 

R-Net(精炼网络)

R-Net 进一步减少候选的数量,使用边界框回归进行校准,并使用 NMS 合并重叠的候选。这个网络是一个 CNN,而不是像 P-Net 这样的 FCN,因为在其架构的最后阶段有一个密集层。

poYBAGSBN0-AT8WoAACmpUD8yVA100.png
 

O-Net(输出网络)

这个阶段类似于R-Net,但这个输出网络旨在更详细地描述面部并输出眼睛、鼻子和嘴巴的五个面部特征点的位置。

pYYBAGSBN1KAV3NOAAB3GFjphhE939.png
 

TensorFlow 实施

为实现 MTCNN 模型,使用的工具是 TensorFlow 和 Google Colab。TensorFlow 是为 Google 开发的 ML(机器学习)开源库,它能够构建和训练神经网络以检测模式和相关性。Google Colab 是 Google Research 的产品,允许通过浏览器编写和执行任意 python 代码,特别适合 ML、数据分析和教育。

为了正确实施 MTCNN,必须处理模型的输入和输出数据以保证最佳结果。下图显示了实现的管道的图块。

poYBAGSBN1SAQ7gzAADu67kh1ac171.png
 

第一步是执行图像金字塔以创建不同比例的输入图像并检测不同大小的人脸。这些新的缩放图像是 P-Net 的输入,它为每个候选窗口生成偏移量和分数。然后对这些输出进行后处理以获得面部相遇的坐标。R-Net 的输入必须用之前的输出进行预处理,这样才能获得新的候选窗口。R-Net 输出是候选窗口的偏移量和分数,这些窗口经过后处理以获得人脸相遇的新坐标。最后,对于 O-Net,重复 R-Net 过程并获得输入图像中人脸的坐标。

预处理包括两个步骤,根据之前获得的边界框坐标裁剪输入图像,并调整裁剪图像的大小以匹配模型的输入形状。

pYYBAGSBN1aAUBDzAAAeOtktOiU097.png
 

另一方面,后处理包括三个步骤,应用NMS合并重叠区域,用之前获得的偏移量校准边界框,对最终边界框坐标进行平方和校正。

poYBAGSBN1mAMEaWAABJRZfbQ90293.png
 

之前详述的所有过程以及 TensorFlow、TensorFlow Lite 和 TensorFlow Lite Micro 的模型都是在下一个 Google Colab notebook 中开发的。

在 Colab 中打开

部署到 ESP32-S3

模型开发的最后一步显示为所有 MTCNN 模型创建 .c 文件和用于模型设置的 .h 文件,它们位于main/models/. MTCNN 管道所需的预处理和后处理函数是使用 C/C++ 在文件utils.cc和中实现的utils.h,这些文件位于main/.

硬件包括 ESP32-S3-DevKitC-1-N8R8 和 OV2640 相机模块。PSRAM 的使用是强制性的,可以使用另一个带有 PSRAM 的 ESP32-S3 代替 ESP32-S3-DevKitC-1-N8R8。

1. 下载并安装 ESP-IDF

本项目使用ESP-IDF v5.0开发,必须使用该版本或更高版本。下一个链接包含下载和安装它的必要说明,请进行手动安装。

下载并安装 ESP-IDF v5.0

2.克隆这个存储库:

git clone --recursive https://github.com/mauriciobarroso/mtcnn_esp32s3.git

3.配置项目:

更改 menuconfig->App Configuration->Camera Configuration 中的值以配置相机引脚,并在 menuconfig->App Configuration->Wi-Fi Configuration 中更改值以设置 Wi-Fi 凭据。

cd mtcnn_esp32s3/
idf.py set-target esp32s3
idf.py menuconfig

4.闪光和监控

该项目不需要屏幕来显示 MTCNN 生成的图像和边界框。相反,它使用控制台字符来打印输出图像和其他相关信息。要监视控制台输出运行:

idf.py flash monitor

控制台应该像这样打印一些东西:

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x17d8
load:0x403c9700,len:0xe88
load:0x403cc700,len:0x3000
entry 0x403c9930
I (25) boot: ESP-IDF v5.0 2nd stage bootloader
I (25) boot: compile time 13:50:38
I (25) boot: chip revision: v0.1
I (26) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (33) qio_mode: Enabling default flash chip QIO
I (39) boot.esp32s3: Boot SPI Speed : 80MHz
I (44) boot.esp32s3: SPI Mode       : QIO
I (48) boot.esp32s3: SPI Flash Size : 8MB
I (53) boot: Enabling RNG early entropy source...
I (58) boot: Partition Table:
I (62) boot: ## Label            Usage          Type ST Offset   Length
I (69) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (77) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (84) boot:  2 factory          factory app      00 00 00010000 00180000
I (92) boot:  3 storage          Unknown data     01 82 00190000 000f0000
I (99) boot: End of partition table
I (103) boot_comm: chip revision: 1, min. application chip revision: 0
I (111) esp_image: segment 0: paddr=00010020 vaddr=3c0b0020 size=b03d4h (721876) map
I (228) esp_image: segment 1: paddr=000c03fc vaddr=3fc99000 size=05de0h ( 24032) load
I (233) esp_image: segment 2: paddr=000c61e4 vaddr=40374000 size=09e34h ( 40500) load
I (242) esp_image: segment 3: paddr=000d0020 vaddr=42000020 size=a441ch (672796) map
I (345) esp_image: segment 4: paddr=00174444 vaddr=4037de34 size=0b150h ( 45392) load
I (354) esp_image: segment 5: paddr=0017f59c vaddr=50000000 size=00010h (    16) load
I (363) boot: Loaded app from partition at offset 0x10000
I (363) boot: Disabling RNG early entropy source...
I (375) octal_psram: vendor id    : 0x0d (AP)
I (375) octal_psram: dev id       : 0x02 (generation 3)
I (375) octal_psram: density      : 0x03 (64 Mbit)
I (380) octal_psram: good-die     : 0x01 (Pass)
I (385) octal_psram: Latency      : 0x01 (Fixed)
I (390) octal_psram: VCC          : 0x01 (3V)
I (396) octal_psram: SRF          : 0x01 (Fast Refresh)
I (401) octal_psram: BurstType    : 0x01 (Hybrid Wrap)
I (407) octal_psram: BurstLen     : 0x01 (32 Byte)
I (413) octal_psram: Readlatency  : 0x02 (10 cycles@Fixed)
I (419) octal_psram: DriveStrength: 0x00 (1/1)
W (424) PSRAM: DO NOT USE FOR MASS PRODUCTION! Timing parameters will be updated in future IDF version.
I (435) esp_psram: Found 8MB PSRAM device
I (439) esp_psram: Speed: 80MHz
I (443) cpu_start: Pro cpu up.
I (446) cpu_start: Starting app cpu, entry point is 0x40375738
0x40375738: call_start_cpu1 at /home/mauricio/esp/esp-idf-v5.0/components/esp_system/port/cpu_start.c:142

I (0) cpu_start: App cpu up.
I (738) esp_psram: SPI SRAM memory test OK
I (747) cpu_start: Pro cpu start user code
I (747) cpu_start: cpu freq: 240000000 Hz
I (747) cpu_start: Application information:
I (750) cpu_start: Project name:     mtcnn_esp32s3
I (755) cpu_start: App version:      1f8c91f
I (760) cpu_start: Compile time:     Apr 19 2023 14:33:31
I (766) cpu_start: ELF file SHA256:  a41224789833e522...
I (772) cpu_start: ESP-IDF:          v5.0
I (777) heap_init: Initializing. RAM available for dynamic allocation:
I (784) heap_init: At 3FCA5D60 len 000439B0 (270 KiB): D/IRAM
I (791) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (797) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (804) esp_psram: Adding pool of 8192K of PSRAM memory to heap allocator
I (812) spi_flash: detected chip: generic
I (816) spi_flash: flash io: qio
I (820) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (841) app: Initializing NVS...
I (861) app: Initializing Wi-Fi...
I (861) pp: pp rom version: e7ae62f
I (861) net80211: net80211 rom version: e7ae62f
I (871) wifi:wifi driver task: 3fcedb6c, prio:23, stack:6656, core=0
I (871) system_api: Base MAC address is not set
I (871) system_api: read default base MAC address from EFUSE
I (891) wifi:wifi firmware version: 0d470ef
I (891) wifi:wifi certification version: v7.0
I (891) wifi:config NVS flash: enabled
I (891) wifi:config nano formating: disabled
I (891) wifi:Init data frame dynamic rx buffer num: 32
I (901) wifi:Init management frame dynamic rx buffer num: 32
I (901) wifi:Init management short buffer num: 32
I (911) wifi:Init dynamic tx buffer num: 32
I (911) wifi:Init tx cache buffer num: 32
I (911) wifi:Init static tx FG buffer num: 2
I (921) wifi:Init static rx buffer size: 1600
I (921) wifi:Init static rx buffer num: 10
I (931) wifi:Init dynamic rx buffer num: 32
I (931) wifi_init: rx ba win: 6
I (931) wifi_init: tcpip mbox: 32
I (941) wifi_init: udp mbox: 6
I (941) wifi_init: tcp mbox: 6
I (951) wifi_init: tcp tx win: 5744
I (951) wifi_init: tcp rx win: 5744
I (951) wifi_init: tcp mss: 1440
I (961) wifi_init: WiFi IRAM OP enabled
I (961) wifi_init: WiFi RX IRAM OP enabled
I (971) phy_init: phy_version 503,13653eb,Jun  1 2022,17:47:08
I (1011) wifi:mode : sta (7c:df:a1:e1:d6:4c)
I (1011) wifi:enable tsf
I (1011) app: Connecting to CASAwifi...
I (1011) app: WIFI_EVENT_STA_START
I (1031) wifi:new:<3,1>, old:<1,0>, ap:<255,255>, sta:<3,1>, prof:1
I (1761) wifi:state: init -> auth (b0)
I (1801) wifi:state: auth -> assoc (0)
I (1851) wifi:state: assoc -> run (10)
I (2011) wifi:connected with CASAwifi, aid = 14, channel 3, 40U, bssid = b0:be:76:04:3e:16
I (2011) wifi:security: WPA2-PSK, phy: bgn, rssi: -44
I (2021) wifi:pm start, type: 1

I (2021) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 0, mt_pti: 25000, mt_time: 10000
I (2021) app: WIFI_EVENT_STA_CONNECTED
I (2141) wifi:BcnInt:102400, DTIM:1
W (3001) wifi:idx:0 (ifx:0, b0:be:76:04:3e:16), tid:0, ssn:6, winSize:64
I (4881) esp_netif_handlers: sta ip: 192.168.1.21, mask: 255.255.255.0, gw: 192.168.1.1
I (4881) app: IP_EVENT_STA_GOT_IP
I (13401) app: Initializing SPIFFS...
I (13451) app: Partition size: total: 896321, used: 0
I (13451) file server: Starting HTTP Server on port: '80'
I (13471) s3 ll_cam: DMA Channel=4
I (13471) cam_hal: cam init ok
I (13471) sccb: pin_sda 4 pin_scl 5
I (13471) sccb: sccb_i2c_port=1
I (13481) camera: Detected camera at address=0x30
I (13481) camera: Detected OV2640 camera
I (13481) camera: Camera PID=0x26 VER=0x42 MIDL=0x7f MIDH=0xa2
I (13561) s3 ll_cam: node_size: 3072, nodes_per_line: 1, lines_per_node: 16
I (13561) s3 ll_cam: dma_half_buffer_min:  3072, dma_half_buffer:  9216, lines_per_half_buffer: 48, dma_buffer_size: 27648
I (13571) cam_hal: buffer_size: 27648, half_buffer_size: 9216, node_buffer_size: 3072, node_cnt: 9, total_cnt: 2
I (13581) cam_hal: Allocating 18432 Byte frame buffer in PSRAM
I (13591) cam_hal: Allocating 18432 Byte frame buffer in PSRAM
I (13601) cam_hal: cam config ok
I (13601) ov2640: Set PLL: clk_2x: 1, clk_div: 3, pclk_auto: 1, pclk_div: 8

5.测试

将设备连接到先前配置的网络后,将相机指向任何人脸。控制台输出应该打印这样的东西。

P-Net time : 65, bboxes : 3
R-Net time : 232, bboxes : 3
O-Net time : 789, bboxes : 3
MTCNN time : 1088, bboxes : 3

要观察摄像头捕获并经过 MTCNN 处理的图像,您必须访问以下链接http://ip_address/faces.jpg,其中“ip_address”必须替换为分配给设备的 IP 地址。它应该显示这样的结果。

pYYBAGSBN1uASXTIAAALN1BQ7ZA931.jpg
 

特征

  • 形状 输入图像:96x96
  • 格式输入图像:RGB888
  • 检测距离:10 cm - 100 cm
  • 响应时间(1 人脸):大约 1000 毫秒

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.lene-v.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'使用MTCNN和用于ESP32-S3的TensorFlow Lite进行人脸检测',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.lene-v.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);