Wio Lite AI视觉开发套件——人脸识别快速实现
1 Q& S6 ]% o: ?5 e& L4 ?6 a) n$ A8 o1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务 W9 [- J; J) d1 A
2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,7 ~& E% {; n! T, S
9 z8 _' f8 ?& X6 c6 z+ Z- @5 q- y# k+ L
采用如下接口对应联络到WIO Lite AI开发板,
4 a! l8 J7 p) `# Y( Y7 |
% `. j0 u/ k6 d4 {% i4 ]
" i3 N& [5 ~ F# s
使用调试夹子快速连接,就可以,如下图,
& u" F( M( W! g3 X: x
5 ]& N8 U% t+ o2 W在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
8 S# s+ }0 B% B9 b) k% o6 F+ o# [0 w
m& S7 }/ _5 R( N9 F6 ^2、创建模板项目,启动CubeIDE
2 `- Q& s" N0 y8 |! {* J
8 A/ O0 |3 [% X' W1 f可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。8 \' |: m' o, _ E
完成编译,执行下载,显示成功完成。
$ z+ {0 ^+ w8 q0 [; l8 ` `; y
' c. R: [' u" e1 x# l
; [# T( U7 @$ ^3、运行模拟
8 i! O% }+ t( I( z" A上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,/ B2 I5 L4 L! R) G$ o
这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,. x4 T( @. k& z1 [8 Z) N+ s! O; r+ N( l
5 _5 H/ S+ s. S: n1 O2 S
& m6 s( d! a4 S" ^$ y
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。5 G* L# V7 I. p' Q4 w
; p2 l0 Z7 `8 O5 {1 L' O
) h) @ x- Y4 `: ?* K6 a
这样快速监测成功。
/ @" r! _% _) }& K, M' V1 P. U8 _4、人工智能实现的分析5 x& L- v9 R' C, a- ?$ B
4.1 硬件平台的能力# O+ x# P+ W8 G/ y' f1 n
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
9 b7 Q) W7 z7 K6 T7 `; q0 ~- y! J- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽: O( O% Z1 b: c6 t8 J7 g; W. j& S6 z' k
4 G: I% I/ O+ s, U2 G& r; b
+ N% P& E6 U3 q3 A$ p; e8 K4.2 人脸识别的流程和库的支持* S) A1 }! `7 B+ Y. H- I
CubeAI的人脸识别是用如下层次实现' v: e" v& i2 l( b4 q, Q* R+ S! K
4 q0 M, W) ^1 }
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下$ k$ C( G1 n; i3 y
^ ~. I0 q7 Q" }- K7 p
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来; j j# R5 w. @! {7 s9 l+ `$ d; t5 o
4.3 程序代码分析
: ^" h8 `7 a. X7 c/ F4 A首先定义图形数据的交换空间,是一个320x240的采样空间: z% N2 ]) E5 q- h. }" V$ [
- static Frame_TypeDef frame ={ .buffer = buffer,) j0 d/ ^( C+ A2 _
- .length = 320 * 240 * 2,! h/ b9 c9 G( R; F) b$ n; n
- .width = 320,2 u8 \8 V% Y5 j& u% |7 x* E9 A
- .height = 240
5 N+ k* ?1 h) ~' B - };
复制代码 主程序代码非常精简2 B; v" _3 U" [( `7 C4 @
* l# L% `: P( O8 q9 ]$ }; X- int main(void)6 `' n L" l9 k% T) ?4 m
- {! r. R2 T. H- N
- MPU_Config();7 N8 `6 }! I5 s: a6 L8 W
- SCB_EnableICache();
: o, `, ]7 f) R f - SCB_EnableDCache();7 l" q5 k& d1 a' i
- HAL_Init();6 i' z6 u6 R% {4 Z% m1 t* r
- SystemClock_Config();
8 m* d; ?. w7 \
, W5 o8 l8 j- g- /* Initialize all configured peripherals */ Y" B4 b7 h1 E" n; {+ T
- MX_GPIO_Init();
3 Z! d4 V) z, n* K - MX_USART3_UART_Init();
! a) F0 B( [: z+ m - MX_LTDC_Init();
7 d; {6 x# l! a* ] - MX_I2C4_Init();
% a }2 j$ f K3 m - MX_DMA_Init(); |' K e3 m$ |0 w1 W1 r
- MX_DCMI_Init();
6 h; E* Q: r( e- D1 y( W - MX_TIM2_Init();
- R( ?% z# B" H( o0 n# K - MX_OCTOSPI1_Init();
4 T {+ }* }/ Z2 I1 t) ^ - MX_CRC_Init();( V# }4 R" h6 b: _0 A6 L3 ?
- LOG("here");
$ u, j; k }" `, }! U$ U - Psram_Init();9 I+ v3 {% R! R2 H( P, O
6 p0 H1 A+ T! h- /*OV2640 Init*/
4 i& h3 _ ~' q& P/ P+ T - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK3 v% E- \/ t) H: V$ v" Y* o/ j
- OV2640_Init(&OV2640);$ |" m' A p# o4 X( _( i8 x) f
- OV2640_ReadID(&(OV2640.ID));
0 i/ O( ~4 v2 t$ i; S, s$ U% h - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);
5 V; t) I7 {- T' ~: n8 x( ? - OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.1 d* N1 z$ P9 t: b
- OV2640_Flip();
' ] E$ G$ d; v4 l. Y: D) G - OV2640_Start(); //initial IPL and AI4 [! G7 I6 p( I) I) d, X
- STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);% k C* e+ ?; G9 t& A; P
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */7 K- r( G3 _: @$ D
- __HAL_RCC_CRC_CLK_ENABLE();: T0 x. M+ X( q1 ^/ r: j1 C, G7 k; n
- aiInit();
6 K3 Q: Z( {- A6 Z+ J, }1 c5 l" ^% p - frame_rgb565.data = frame.buffer;
; W+ R6 h8 h+ j0 n/ E - 4 a5 ^ o" n/ \; a" V
- while (1)
, Q# \( g% {7 P1 h - {
$ g1 r1 ~' f7 M4 q( N - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);" @# R+ j4 d0 Q5 k
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);8 [( E- w6 N+ o1 H, w) m
- 7 c `) P5 Q$ O, b
- // rgb565 320*240*2 to grayscale 320*240
. ~' @& ^* U; I$ P( q - if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {" A5 S9 v2 J1 S0 x* Z
- while(1);
, k0 x5 \; w' g* P - }
2 V- u: b) ~) ~( O+ B5 J8 X - // grayscale 320*240 to grayscale 96x96x2
/ ~( k( O4 T% S1 |7 U - if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {# [8 [. ~, E+ `1 n( P2 g) G, _
- while(1);
+ H2 a0 S& Q8 U! Y - }
8 }% X. j1 X* B1 k
( ^3 [/ ^, p' K# l: m' o- //AI: f- k: w" i) S7 Z( \3 ~3 w0 \- F8 o
- aiRun(buffer_grayscale_resized, network_output);2 D1 w- T! P* o
- postprocess(network_output);* p, ~" U t6 u
- * C% @! x5 s; ^; F" d' C6 e
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
+ V5 d6 f" I0 K* v* ]: H* x - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);! b; U! f4 `; x1 u) I. D
- : a1 X7 Q1 k: k6 p% Z r. L# v7 B
- }6 ^8 y( a9 r' j& O4 M$ v) m
- }) `$ N0 c( }# [$ R
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,
) c& { l; z5 v# f! C* Z* |- O实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果
* k. v) {; \" x$ C& Y( i; \
& i& _6 U6 \* Z- aiRun(buffer_grayscale_resized, network_output);
4 F7 d4 D2 c. v# R2 f" |0 M - postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,
, m" Y9 `) l5 F% K; M* Y% R, Q2 g- void aiRun(ai_u8 *pIn, ai_u8 *pOut)5 W1 Y5 X/ K8 F9 T% W$ P
- {; k" q! ^) }1 ]5 ~) _1 C- z- x e
- ai_i32 batch;' X" [% C* P2 T- O2 H
- ai_error err;: t" F7 f. x0 t) i
) |3 b$ l- \) P! b6 P2 J6 Z- /* 1 - Create the AI buffer IO handlers with the default definition */1 b) O/ E! \$ K- O% `
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;
& |( H4 g8 q! u: X- j" | - ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
( U2 @9 L5 E2 `) z3 s3 F, L& H/ u - 6 E8 n Q4 s+ C
- /* 2 - Update IO handlers with the data payload */( W& G: L: Q& V: o
- ai_input[0].n_batches = 1;+ i: q& \$ O6 j7 ^' l9 r( v
- ai_input[0].data = AI_HANDLE_PTR(pIn);
6 V+ e( J! y0 U2 u - ai_output[0].n_batches = 1;7 B: T+ R4 o! D2 x9 z
- ai_output[0].data = AI_HANDLE_PTR(pOut);' A( B0 V8 U0 t6 @; c6 s5 m
- 1 }4 |' s) a0 m( p# G
- batch = ai_network_run(network, ai_input, ai_output);* w6 B& E7 @9 o3 y: {
- if (batch != 1) { r' i& D0 S# V2 b0 d( B: c; T
- err = ai_network_get_error(network);
' y1 {0 [' |0 t$ L* E - printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);
+ u& T4 B% ~% O, R& X; S; W5 X; n - Error_Handler();/ t) \2 I8 G: \" h& @* m% u: z/ t8 R8 v
- }7 t" h+ b7 G) n8 E5 F& J0 t4 b: Q7 {
- }
8 X# a! u& b! m; P
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,5 n0 R; S" o- B) U/ P! |) B2 a8 U# W
- ai_i32 ai_network_run(& y) E5 H+ Z- s# G
- ai_handle network, const ai_buffer* input, ai_buffer* output): F! J( K f+ `) \$ U
- {3 O4 m7 k, E( e) E( }8 a/ Z, S
- return ai_platform_network_process(network, input, output);# H0 s1 D& O* H' E+ A
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。" n, n+ w5 I) y: `* O
3 s/ j! {8 j4 ^9 X8 J4 b' s5 小结 y4 f- l3 E+ v# |
基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。) Z c4 `7 | ]7 w" Q' F
在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。' ]- R+ K5 O" x& n( T
: Q' N* C7 r# R) r! S5 D0 s- x3 X& X) o( ]# h6 m
- j v" {3 y5 V- s) a
/ } U, J. I! j5 I) p' I
2 ^8 z" G/ u$ |. J% H6 P
9 O8 U- H: \) s$ Z& c$ v* h- d1 e) n o( f D8 \, x1 C
* }. S( ?- R3 N6 l
$ j+ |- I3 |3 V3 }# _0 [0 |
. g5 r' L& l7 z$ L# k. X
|
/ F' M z/ P2 J6 `+ ]9 B' e
大佬求源码
UP求驱动程序