Wio Lite AI视觉开发套件——人脸识别快速实现5 q9 [: j* F& ]. Y) r* d( f( K
1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务
# w" y% q! y- i0 ^2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,
) e5 c; e# l! N
1 ^/ v9 u8 g/ F; s采用如下接口对应联络到WIO Lite AI开发板,
1 D4 r8 R. r9 }
6 c& l5 n' S7 k$ R
7 ^( D; ?1 l9 H1 }3 u
使用调试夹子快速连接,就可以,如下图,* ?5 h0 i7 X7 q' A) x
, ^0 J' O# O. M$ N G) h% C& ], C8 J在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
" e- w% E3 m4 A- ?. w
9 U) {- [3 c; t H
$ r& H* g- ~1 f: g: q1 g$ b
2、创建模板项目,启动CubeIDE, P( i+ f9 X A4 H9 e8 |. M
1 e M2 t+ O+ c W; G2 A! }. V可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。7 G* @) g# M: ?9 D- `
完成编译,执行下载,显示成功完成。" u0 a* R1 b& x" I5 m$ J2 @
$ I1 x8 g A9 v
: p0 j8 |0 Q- G0 G6 g3、运行模拟
( z4 Q" K* T# g( c. |3 _上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,* Y3 S9 y( D5 F( |- D
这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,
4 ^: |4 A) i6 E
, v) b9 j* j. g
( C8 A5 t$ @+ ^ E. D7 b; K( Z) Y移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。7 B9 R) G9 v, o
" Q% B5 G$ C' n @ z& ]
" ~$ t; A6 H8 i# b2 K
这样快速监测成功。
8 z& m6 {, g& i& f; \: d8 X4、人工智能实现的分析
( ^3 f" B* D7 i7 a1 o" ?, Z3 Y7 K4.1 硬件平台的能力2 Q6 ?- S1 [: s/ I5 N \ o! I% K
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
+ W3 A; |, {( l z W- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽5 X: l. u8 s4 [. H. K6 g$ Z3 P
, y# {% q' P- K3 D9 r3 d
3 _$ g/ F5 @, l
4.2 人脸识别的流程和库的支持
8 B+ {9 {+ q2 a9 T7 p8 ^& i9 [CubeAI的人脸识别是用如下层次实现
3 `1 E0 m7 O& E3 u& v
2 u6 z. Y H# b }( A/ R
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下- N# q+ I; [2 `1 ` e% F W# n& n0 Y
1 P/ t: v6 {, S数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来" y$ l. q$ L9 _0 p1 W9 A$ K! ~$ k
4.3 程序代码分析
( i+ M) D' a) l: W7 {. l" r5 T首先定义图形数据的交换空间,是一个320x240的采样空间* f( ^4 w- z6 k) L: u' S; O: q: F) ?
- static Frame_TypeDef frame ={ .buffer = buffer,
( x+ r% Z; |0 r5 ^- I - .length = 320 * 240 * 2,
& `; k7 I% m; }3 G9 @ - .width = 320,6 D$ R9 D \6 W4 Q' ?8 S* D8 l; F
- .height = 240
/ @4 L7 p+ ^, g; b6 X; J7 Q$ P8 w - };
复制代码 主程序代码非常精简" E5 j- Y, c1 b
- , B/ C- T4 @# \& b$ W
- int main(void)
; h0 r' M a8 L* l7 u9 e5 z+ A2 i$ ?9 d - {
2 ~8 F% O" \+ l2 w - MPU_Config();; g& r0 e; n1 B; K6 y
- SCB_EnableICache();
? i. m% d' d) w: I - SCB_EnableDCache();/ s5 M& q5 f% _
- HAL_Init();
, i' I6 W8 w, X9 N' x& @# y - SystemClock_Config();0 c v7 y* h5 e, C
* @, C$ z0 d1 @1 n- /* Initialize all configured peripherals */4 `! F. y; S$ T5 ]- E
- MX_GPIO_Init();" @! F' a% C. z: {0 {9 p
- MX_USART3_UART_Init();
3 f" ?" u, [: i' f. X - MX_LTDC_Init();
0 |8 H; _; |! M# s. G - MX_I2C4_Init();
. w1 L) W$ c$ ?7 O* { - MX_DMA_Init();2 q. _) A) j2 q) h1 v
- MX_DCMI_Init();
7 k$ }7 D0 R% b9 R( e+ P - MX_TIM2_Init();
2 w8 R6 k& X2 _$ } - MX_OCTOSPI1_Init();, M9 i% B! g# j
- MX_CRC_Init();
4 X7 E9 c r9 ^. @ - LOG("here");
/ |$ F4 q2 |3 {0 u - Psram_Init();
# y- n! _" U7 z5 _+ M
4 O3 q! D) i, R, C) L- /*OV2640 Init*/
8 t9 ~: g& n$ V+ ~) o - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK' d1 g: R: ~; Z; |* F1 K
- OV2640_Init(&OV2640);
2 } R+ f% I+ i' M; l$ E& w - OV2640_ReadID(&(OV2640.ID));1 O8 f" n5 ^0 k. T/ x6 a( M' F
- LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);
7 B, b' w4 [% M6 P \1 l0 i - OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.+ H6 K0 r/ |' v2 _- _! |. {
- OV2640_Flip();
$ K2 w e# ]3 F7 \; t- ^ - OV2640_Start(); //initial IPL and AI
, K# Y5 @5 C! y- S: r$ n# V - STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);, F/ a: E, k# u G. G& J
- /* The STM32 CRC IP clock should be enabled to use the network runtime library *// [/ W" v0 ]+ f* ^6 G1 c
- __HAL_RCC_CRC_CLK_ENABLE();* C6 ~* ?$ w6 q+ C2 e
- aiInit();; o+ U3 @. F9 v0 S: V1 a. p' s
- frame_rgb565.data = frame.buffer;
4 ~# ?* a( C/ D' ?# f, B( @
& ~/ m) X0 ?( M0 f- while (1)2 u9 s6 ]' Q8 c
- {
! k5 F! D0 X; ^& i# N6 D g0 U% o( L - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
% X, V# m9 k0 |, O- O - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);$ o* s% f4 g" x9 @7 T7 j, g9 G, Y- m k
7 o6 b, t- g$ P* T2 ~: N+ ~- // rgb565 320*240*2 to grayscale 320*240: F! T, X0 g# @/ p1 n1 Q# @
- if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {- y7 P Q2 f0 ]: g" ~5 L [# T
- while(1);
2 Y$ A/ w8 f( m, {) Y0 D - }
; b& c( p( `/ `0 b3 J% |/ w - // grayscale 320*240 to grayscale 96x96x2. B/ Q# n) O+ |
- if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {' y7 M i; }; K6 y4 L2 h0 m/ [$ ~
- while(1);
, P) x4 ^% M0 S8 v9 }( @ - }
" X$ f" O+ J+ ]- e% L7 v7 r, d - 7 k# L" A8 F& U; H. o9 P2 U4 y
- //AI
/ ~* Y, I" F9 x! ~; S - aiRun(buffer_grayscale_resized, network_output); t3 k, l) ?, a6 U5 a7 }
- postprocess(network_output);& G' }4 K T: K# C: q* A8 e$ F4 \
- 7 _% s) t2 d4 T4 g; s
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);/ s# q2 u) ~4 d) Q
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);: W4 a+ V+ ~* p9 d& K* ]% i3 ~3 L
0 g% `: h1 h' o) C) b- }
$ p9 X9 D6 i3 Y7 ?; k - }" S+ N8 W/ \$ ~& A
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,( d4 u7 L( H; ^% i- I6 X# W
实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果
4 V7 n( W/ g: {; {. J, H5 G# x1 N
* R! I9 b8 M) N7 r- aiRun(buffer_grayscale_resized, network_output);8 V( Y/ M* Y# v
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,' e! B0 H( K: _ T" }' b& p% G
- void aiRun(ai_u8 *pIn, ai_u8 *pOut), O" d4 {9 A2 C& s# W8 ?; f
- {
8 c7 }0 N" Y, f - ai_i32 batch;) R7 i- J9 J2 @: J- H1 h5 c
- ai_error err;
" `) }* v0 d- O& i
9 y/ V5 j* O; b- /* 1 - Create the AI buffer IO handlers with the default definition */
, b! C# G Q5 p4 {5 l - ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;
0 ~4 v) t6 G" ~. D8 S- z9 P- P2 k( M - ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
3 X5 C" `1 o6 b" X! g
' K) x; W4 F) Q9 g' m( p |1 ?- /* 2 - Update IO handlers with the data payload */$ u# G# |# O& C
- ai_input[0].n_batches = 1;
& r3 X4 P9 u" a9 ^: v - ai_input[0].data = AI_HANDLE_PTR(pIn);
5 Z) }: y, H3 f0 [( c- f - ai_output[0].n_batches = 1;
% [7 T/ [" J4 n/ O$ P6 N- J - ai_output[0].data = AI_HANDLE_PTR(pOut);" B# h, |# k0 H0 u4 W
- 9 |/ ?8 x9 m l8 W' b9 ?
- batch = ai_network_run(network, ai_input, ai_output);& t4 ^6 p3 h6 U) c
- if (batch != 1) {
. L9 {+ ~5 n6 a! ^ - err = ai_network_get_error(network);! j/ V% T1 M) p. P
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);
N4 b8 U! K3 o0 O! U - Error_Handler();1 V/ r$ N4 d3 \' i' n/ c' Z/ c! m
- }
2 W* W4 a, @3 h* S$ E - }7 D$ ?! n% e% b/ L$ I
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,
. q( f5 j9 m/ J7 c0 N- ai_i32 ai_network_run(
7 i' u4 [7 _6 `+ |3 ~2 o - ai_handle network, const ai_buffer* input, ai_buffer* output)" L# n8 `* a W- y
- {
; _4 k3 J# S3 ~. S4 i! m" P" O - return ai_platform_network_process(network, input, output);
& ? b. a0 q* p. h( X - }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。2 F( K' @; X2 N0 X' Q
; C0 o A0 |; A# j. p5 小结
/ W- R( W* Y1 E, h8 c 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。
' R, ^8 _* Q* e7 V$ \) B% a( E* V 在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。5 Y3 U! z3 R0 ?8 g% i: G, `
% U; l; `2 ^' H; A4 p, @8 o, h4 ]3 }" D" q
+ P U, K. Q$ I8 K* f- z: s7 \; K
' b& q; \ n5 w" s" j( E) s% [2 w9 t& d2 a9 ?5 l
+ @* v$ _3 L/ k# }! S; h3 M4 n8 D
: M$ ?6 }: b3 L) W$ _' N+ x% j7 m4 S: g: }: z+ r
% @7 x+ D% d0 l. k% u1 j4 q6 F |
- E" s3 w4 @4 L( y: E
" T3 W2 X* k. a