Wio Lite AI视觉开发套件——人脸识别快速实现
* K8 |9 M/ [+ g$ k/ c) q* \1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务
- C5 R4 o( S1 Y, L. A2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,( d0 Z3 k( O6 i% w! D
; z4 R- D+ b7 T( B4 V, m采用如下接口对应联络到WIO Lite AI开发板,0 F0 N; e/ E% z3 b1 l: v
8 C! k2 S7 V1 s$ o: C
5 |+ Q6 L U, o1 n( C使用调试夹子快速连接,就可以,如下图,
$ _" V, q o" \8 d( J
1 q- {- d! r5 o3 X, {+ X
在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
: g, I6 y9 \0 {( u' H/ N' l$ P8 Q: p$ v( }# d) e8 F( p
( d5 t5 A5 s7 ^2、创建模板项目,启动CubeIDE
2 X% v' P, ^ x. d
5 z r& h% w4 N可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。' q* I. p6 ?! ? w9 h
完成编译,执行下载,显示成功完成。
+ n7 c. c" |8 ^: v
( F* r4 C) p" f* h
( W' }4 d6 o! m# F+ `5 ~3、运行模拟
& j+ j8 E( T2 ~7 W* `, b9 c* d上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,# \ V: q( R+ ?4 _
这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,) }4 I4 i, K. S* h; L- \% _' X
" ]: D/ o* D+ t/ H2 D# }1 }
( V* J# n# m+ }
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
?8 d5 ?# o. X& b+ n2 ?+ ?# q0 g1 @
1 x$ ]$ x* m' R
. P: y; j! L( `( O% v+ m, \0 y这样快速监测成功。9 ~' q+ A& Q# Z' x% \) I4 G
4、人工智能实现的分析
8 K2 ^( |! N. `1 ]9 e1 p8 ]4.1 硬件平台的能力
" B! q# u+ g& W6 U3 i% Z/ n1 sWIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
8 R. P% K' _0 h9 [( u# L9 b+ G- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽
7 e5 g4 C$ E& ^; \1 [: i. H 8 B P- p7 k5 S) z
; h' R; W( h" H7 Z5 d* c; V
4.2 人脸识别的流程和库的支持
, h% Y: W8 Z+ e' p2 k2 {8 W- j8 wCubeAI的人脸识别是用如下层次实现% s [ v& @& L& f! ^
& S" ^ r q+ Z" P: X5 Q' R# }
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下
7 h1 @+ b: q+ _* c% h" K8 s
% c& j; l ^3 K4 d0 N7 _
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
( b& e$ ?7 {$ ^4 H4.3 程序代码分析
; F2 _3 L2 m5 D6 h ^/ c x/ r首先定义图形数据的交换空间,是一个320x240的采样空间% x4 C) ^* H0 s7 G" j0 D
- static Frame_TypeDef frame ={ .buffer = buffer,/ V5 S+ q! A* E5 [
- .length = 320 * 240 * 2,9 E# d4 K; [" _
- .width = 320,2 Y3 l& g# Y/ M* C
- .height = 240' [, V6 ?$ D* r8 e
- };
复制代码 主程序代码非常精简 |3 @ f7 _6 Z
- 2 M' i+ i; n C4 O. P# W. u/ T0 T
- int main(void)
$ O2 m( W+ d& l% s* _9 V7 d) C - {
- ~0 }- }. r' P- h! t - MPU_Config();* }% @& s3 e5 I2 j8 P0 `
- SCB_EnableICache();
. e& L; W: W. N1 n - SCB_EnableDCache();
. w. D% \0 n2 J8 E - HAL_Init();7 M* b0 K& D4 C3 L$ Q) E5 |
- SystemClock_Config();' D" f- m9 F, ]# N/ v$ G/ K* J
# D! p5 C9 u; B4 w! T8 S$ M+ x- /* Initialize all configured peripherals */
' C7 D$ h7 t' a' Y4 m - MX_GPIO_Init();
c5 ]6 M/ h/ `6 F- _ - MX_USART3_UART_Init();
& B" N1 i' I3 J. o - MX_LTDC_Init();
0 F7 }! q; W! @- q' o$ ? - MX_I2C4_Init();( P" L+ R+ |: ~: A
- MX_DMA_Init();
) J' R8 [. j# z% u$ O$ _; T - MX_DCMI_Init();# Q" \" o) P! D0 M) p" I4 h
- MX_TIM2_Init();7 Q# p- ^, ^4 J9 A+ ]6 F
- MX_OCTOSPI1_Init();' C1 G4 h" i# o! F9 z, D3 B- c" {
- MX_CRC_Init();5 ^, i1 E4 E. T5 x4 T* W, O
- LOG("here");/ D( E% b3 L( f r
- Psram_Init();
5 Q4 B J) ?( F$ S
7 Y6 I/ k) o, D. `% [, D9 i* o- /*OV2640 Init*/
* ]. R3 w$ R/ ~* w* }+ H/ _ - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK
: W( L' x8 F& a9 F* X) @7 J3 N - OV2640_Init(&OV2640);
" y k8 W9 D* k0 R9 E3 q$ K) a8 W" u2 T - OV2640_ReadID(&(OV2640.ID));
6 i+ ~4 M/ R. G* A0 I - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);
& a; z' m+ d) C! w* `4 B6 o - OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value., ^! O/ q- _0 u5 D& h. f
- OV2640_Flip();
7 r* Y+ Y: Y, r - OV2640_Start(); //initial IPL and AI
) @" j/ ^8 m: s& L9 Q3 K - STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);) W R" L+ ^4 {/ w
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */. Y+ d3 N4 L( l- _5 i0 I
- __HAL_RCC_CRC_CLK_ENABLE();
6 \/ l+ t! ~1 L4 q1 f - aiInit();+ \* h) b4 \1 Z+ h3 F( D
- frame_rgb565.data = frame.buffer;$ D3 d0 M# m. A4 ^: [ _6 h
1 ?" p3 H1 _5 H' }- H5 I7 m% r- while (1)/ @4 d) x9 O4 d9 w
- {
- K* Q2 C0 G% _! X( U - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);, Y% E2 z6 P5 @8 o
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
- T+ _' k* o2 |, m - ; D- W3 W+ R( r6 ?* [# H
- // rgb565 320*240*2 to grayscale 320*240& D( D' U) B( ] Q
- if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {
; n9 y5 \/ Y' l8 ?3 R - while(1);0 @/ {5 s0 S; E5 @% Z
- }, R1 u0 M% u. g- j) w3 K: d: R4 q) I
- // grayscale 320*240 to grayscale 96x96x27 E3 \- ^+ x0 e7 n& U( x& f
- if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {
" h* h' y. D; U. { i, H% F - while(1);+ M4 @; g" D6 z: ` [
- }
- g% Y& H9 V4 \
5 x1 Q, ]5 j7 i- //AI5 K/ ]# q' `* E: q( B* ~3 }% D3 \$ P
- aiRun(buffer_grayscale_resized, network_output);
; t6 C' C. u8 A" ?" O8 L$ B& `5 c - postprocess(network_output);4 n8 p6 U" p$ z& K, U0 ~( X0 G
- , B+ x- Y) i6 _, \
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);& f' D/ f& Y- M* U5 w
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);, F# S& G4 b- @) i+ R; N' z x0 J6 C: \
- 7 x S5 |5 t8 D
- }
8 v5 |; ?! P$ J1 @ - }9 N" i. D* r8 m4 w6 M
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,
6 ?4 B2 y7 T% _实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果8 \7 }$ H& o8 R
9 a$ c9 k$ `& E; ?
- aiRun(buffer_grayscale_resized, network_output);0 N1 K2 W, v" b! q* b. F
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,
* { `0 r" M) ?- @. y0 ?1 u- void aiRun(ai_u8 *pIn, ai_u8 *pOut)
! T& W, K8 o- U& f5 m' y - {
, n/ H, b: { X& h# B - ai_i32 batch;. K4 r* J) E* S" a) T4 v7 ^$ l3 b, _$ Y
- ai_error err;# Q* r# p, F: X$ T0 C
7 V2 T9 {1 p$ |7 s+ L, o- /* 1 - Create the AI buffer IO handlers with the default definition */
2 [( S J5 n. J. `3 a& y - ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;
" ~' G' M" m) H6 @$ ? - ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
1 ^3 V& N7 L: J' M$ Y - e+ O8 `5 c; H$ R
- /* 2 - Update IO handlers with the data payload */5 M: X, }% ]4 g9 I' G" f" b( R1 x
- ai_input[0].n_batches = 1;
- g6 I$ `; p& K: b3 H: ^ - ai_input[0].data = AI_HANDLE_PTR(pIn);
2 i/ T8 s2 b- b/ ~3 N N - ai_output[0].n_batches = 1;/ b# `3 j' G6 }+ z) s0 X
- ai_output[0].data = AI_HANDLE_PTR(pOut);
, y; {3 x1 Y5 S3 i$ E. Y4 q
8 I9 t6 Z$ e4 J! y# K+ _, t- batch = ai_network_run(network, ai_input, ai_output);0 D7 _# h9 d' m3 [9 Z' `
- if (batch != 1) {
% G, d5 v* A5 a6 W+ A - err = ai_network_get_error(network);4 e! J2 v/ K' x, \
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);' {# x9 P4 n( J% z6 |
- Error_Handler();
M7 J5 C2 {' g3 k9 ^2 y - }
, ?& G( n4 x) B - }( G% u( a" j0 Q: H
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,; V1 D: S' @7 y1 C' L
- ai_i32 ai_network_run(; x6 B* r$ j0 @4 Z c
- ai_handle network, const ai_buffer* input, ai_buffer* output)
2 J2 t9 D3 C1 A5 r - {
5 k- \# C8 `5 F9 J! ?& p0 d - return ai_platform_network_process(network, input, output);- y$ k) I; l S2 c
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。* t8 y7 ^8 T: `0 T- ]
1 j5 s4 H2 \+ ]$ l ^! \( h
5 小结
( y, n& I% z1 y8 w" w9 T) G/ X6 L$ v 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。
& ]& T# H! ~1 c, J7 w& s* O 在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。
; z$ W/ e1 K2 r2 @6 s! x1 @5 l; Z) r& Y7 d* d4 ?$ u5 W1 p) i
- c& l' I, E& |
; i" U& @" D/ S1 S% l+ j
3 M( F( ^" a0 y3 s
# C& \ `: E; V4 z" h) H& Z' G) [9 z5 y
- E% j* o! M/ V8 V' F) w1 D. r" W. @8 u7 o; v2 x, }2 u* ]# C
( |. B. D4 @4 p( Y C+ L Y
% l( ]2 c% ~& ~9 ]5 `. [7 L
|
1 d( d* j: O% v. C' _# c2 o; B7 t" ^6 k