Wio Lite AI视觉开发套件——人脸识别快速实现" r/ A& d8 x8 F" _0 O. y3 }' W
1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务0 ?- h( k$ l) p& g3 d
2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,4 g* E, d$ [) m8 U* @
9 T$ N/ _% V$ L- P
采用如下接口对应联络到WIO Lite AI开发板,0 C8 T+ v1 U! ?4 T6 v
) y& q" l, O% O7 M- C
+ K! G! b4 O3 K$ \% b9 q. H
使用调试夹子快速连接,就可以,如下图,
$ n8 u4 P; L) |* `* C d- Q
5 {6 ?; B+ O/ w' g在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI, T b( U7 v1 j) B/ Z4 q/ L
" k0 B7 P3 X0 o: Y9 H
; d, E* r) r; y0 r
2、创建模板项目,启动CubeIDE; I9 R& c0 s( l9 | m& c4 x! f
/ Z! C) ~3 |$ [" \! [# V7 K
可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。+ |! L( I5 z% C9 L3 u
完成编译,执行下载,显示成功完成。
2 H9 O0 |! ~. m# q8 e0 Q. U1 H* l6 x
. J0 p; i% q3 o7 K2 G
6 o- p F/ c* J3、运行模拟
0 q5 @- U: J t! c3 L" I4 \; d上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,+ Y0 E. _& _" Z
这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,) q7 @, B. x6 n1 D+ C$ N) U! ~
/ [8 F, x) k) u% G9 c
+ q+ d7 |1 I* f2 X. }: p
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
( T3 a' d; E* v% g
' B- P9 j6 S- }, R+ h4 |0 W
4 G1 C4 E |( x. t( A
这样快速监测成功。) m# C! X; y5 v$ B3 e& f
4、人工智能实现的分析
, ] I. S$ w7 S, R5 C& a7 i1 n: q3 H4.1 硬件平台的能力3 d8 g; ?" Y. W4 O9 a1 D
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
2 A( E. g& s. t0 H# r- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽
, f8 J1 g9 C% W% J2 o
- @& o6 b6 _5 g( T' w/ b: e% X& m0 l- c0 f
4.2 人脸识别的流程和库的支持$ Z" `* x4 ]- O9 D
CubeAI的人脸识别是用如下层次实现
. W1 q! `% X4 [% j3 e
' W9 O; Y! N7 f& Q g0 _1 r L+ g
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下; o) p3 e# O; G
: N$ r' k2 f9 y1 y+ \
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来 K5 P5 m! s9 ~" ^) h, \, G
4.3 程序代码分析
, F) d2 P* N" h7 ~首先定义图形数据的交换空间,是一个320x240的采样空间: P& B' C) s. I5 N8 ]7 @& i! o
- static Frame_TypeDef frame ={ .buffer = buffer,
, y0 o7 |, C% ~) y$ o - .length = 320 * 240 * 2,/ W4 t/ |4 |. A$ v R: b
- .width = 320,
: C2 p: L: E4 v. M! ] - .height = 240* L+ i5 d5 {; `$ A+ X
- };
复制代码 主程序代码非常精简- z q4 z% j! g- [1 q
/ A0 X \3 E( D3 R! b" a B- int main(void)# ^* B7 t1 v2 t
- {0 g% l9 A8 \( q3 Y1 y+ _0 z3 j3 N5 }
- MPU_Config();
, s& w; D) [5 K. d; Q$ y( X - SCB_EnableICache();; e. p5 r' U/ Y- j) t8 L5 M
- SCB_EnableDCache();
% j# k. {5 ]- [) p - HAL_Init();9 l* Y) Y! E' f3 s$ m1 L& n2 y4 F b
- SystemClock_Config();7 f0 g5 W8 U7 T% o
6 u8 x% F& M4 T: |/ l- /* Initialize all configured peripherals */# V4 D0 o6 v, I1 f7 K1 E
- MX_GPIO_Init();; j9 I' R9 S, T3 j+ P& ^: i
- MX_USART3_UART_Init();
0 P) I) Y+ b" \3 T# P4 [ - MX_LTDC_Init();
* U0 u3 \: f2 f3 G% v, h" _ - MX_I2C4_Init();
j+ n% f8 M9 ^! v; `5 r6 C - MX_DMA_Init();8 O+ W# P7 h9 [! V# E5 g. `, v
- MX_DCMI_Init();5 ~" w; o, k1 J! J. u' ?
- MX_TIM2_Init();
! |; U5 L. [# Z: [/ e# ~ - MX_OCTOSPI1_Init();7 x, B# S' p, J4 }( ^7 A5 D
- MX_CRC_Init();
! W7 Y# F" @/ l) [. [# P$ V2 ]+ l - LOG("here");6 ~# N9 o. w/ C. n% `
- Psram_Init();/ o1 y& Z) A% Q7 E. b
- # c4 Y% o0 V3 v. J
- /*OV2640 Init*/- k" V; W" B3 _/ |) B. s6 _( j
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK) b9 ^ ^, ~3 u4 b3 R
- OV2640_Init(&OV2640);4 O$ A. ?' E3 L3 d, b$ l- O, v
- OV2640_ReadID(&(OV2640.ID));/ A( q$ D: Z, b( @2 P0 o5 A' C0 [5 G# X
- LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);% T1 i2 |8 x: I; B+ \
- OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.. n$ B3 J4 A0 U
- OV2640_Flip();
5 i, \. U3 W! `. {5 ]! B - OV2640_Start(); //initial IPL and AI
/ e8 P! o) D6 p# o! S, I4 h) }; _ - STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);+ N8 r) H0 L: u
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */' a6 B# }, C! R# j0 E J; ~ p
- __HAL_RCC_CRC_CLK_ENABLE();
8 z: p! L0 F* V9 C - aiInit();8 ^9 @# O) {5 J3 j/ ~" {
- frame_rgb565.data = frame.buffer;% R) z V9 L' S4 l! ]
- + b, x+ b8 L, z' Z8 T* ?+ f- }# r
- while (1)% h+ h3 D( [' C) [1 ~
- {+ E) U+ z. e) T* e- M3 {
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);# u6 {: ~5 @* y4 C$ J4 }8 f" O
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
/ f7 f, {; i' `4 G+ l1 ]
9 z& P( d' x' I" E" u- d* c- // rgb565 320*240*2 to grayscale 320*240 V8 R4 H! G- }1 \
- if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {
. ^! {; x# T; A0 v, P3 L# ?( e5 j2 g - while(1);+ e. o7 A1 e* T' b6 F, X
- }0 l- t w7 M m2 m' ?
- // grayscale 320*240 to grayscale 96x96x23 m3 l9 k! ], q* B. C% L
- if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {
4 n$ {: S M0 j0 t g" k - while(1);
. m7 }) X& ~( K - }, S4 [, H: L6 S( i$ }
- . J; B# Z) h$ Y3 d1 T
- //AI1 ?& Y. P( I* f$ [/ y, z
- aiRun(buffer_grayscale_resized, network_output);
% k: @5 h; r D- O - postprocess(network_output);, _! r. t ?% ?5 e9 D: E: O( V
1 s- l7 W% ]0 \3 F Z7 u. T- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);. H" T7 o0 _7 @# i6 h" H
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);
: n1 \* o* n6 \- E, [# a' P
# q5 C& {6 Y, [- z1 y- [+ N- }3 s; g0 J' R$ k, s& W s
- }( C7 K) W6 y$ e; A( G' B7 F
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,, y% o. s W" Q$ H, \* Z$ u
实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果
& u& w. ?5 I% a4 X/ u: X& }5 a
2 A, s8 {" @6 p C# y- aiRun(buffer_grayscale_resized, network_output);
- v2 c1 O% H# \ - postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,
0 y7 [ @* T q; x, n0 ]- void aiRun(ai_u8 *pIn, ai_u8 *pOut)
! H: U% b% e( a% A& V$ p: t - {
- F; r# e, y# {2 H4 r - ai_i32 batch;, d! ^, S. h' R- f
- ai_error err;/ h& {+ _/ a" [& y+ M
! A6 J$ X$ N, X5 |( S W; r- /* 1 - Create the AI buffer IO handlers with the default definition */' i, A8 j9 d" z U* R
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;7 I) S4 \! j V
- ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
# B) V4 T$ b( G% J5 i2 X - 1 K) o! O4 L& u# F$ C% b7 R9 r! W" \: p
- /* 2 - Update IO handlers with the data payload */
$ C" l" d6 i6 q, { - ai_input[0].n_batches = 1;# M3 X1 L3 V$ f( @$ U
- ai_input[0].data = AI_HANDLE_PTR(pIn);. D/ Y% a8 |' c+ j7 o
- ai_output[0].n_batches = 1;
! h2 F s& j4 g( @ - ai_output[0].data = AI_HANDLE_PTR(pOut);6 z8 q: _4 ~7 f& |; v
/ p9 x& L: ~( d. t5 N- batch = ai_network_run(network, ai_input, ai_output);
. s5 }" P. o: a6 A1 b% X: ? - if (batch != 1) {
3 B7 _8 e1 L0 B5 i. b7 B0 J - err = ai_network_get_error(network);: o7 z6 u% ?+ i/ {! B3 O- ~# j8 D+ s- `
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);
' M T& o* O H2 \# c$ a - Error_Handler();, T5 B$ S) y& m/ Q
- }5 q: V8 R; L1 [% S, i/ p# E
- }# h2 d' }$ h' f. j
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,' T) |' G$ J' N3 F6 ?( O
- ai_i32 ai_network_run(
& m9 R7 b* {& m - ai_handle network, const ai_buffer* input, ai_buffer* output)/ ?' R9 U# ^- h" o! g. k
- {9 l. I/ P0 X+ n
- return ai_platform_network_process(network, input, output);
8 \# j/ Z% Q) G) @5 q: o' f - }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。
' K# x( }* j6 M! P% M+ ^" n5 t2 ^7 Z, d9 ] u
5 小结4 H* Q6 Q/ @/ C* X# @
基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。
# X* m+ A! {- @ 在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。
$ b# n2 Q' ?- P8 [4 V( j1 m2 t: e2 a i3 u) Q
5 ^# p2 F8 N- C# `) U5 y
O- S3 S8 F( F+ F5 ~/ j2 U% i( |! {. n) a- G
5 c( j1 J' G; o( p* y# L9 o/ v
1 e: L2 |" I3 K$ w: X# [9 S* q v# b7 `' a
- j! [: N' z7 `
2 C) b* t* @4 F& C5 u6 D- e: E7 R0 e3 ~9 N1 u8 c2 @
|
5 l& U: x: A x
大佬求源码
UP求驱动程序