Wio Lite AI视觉开发套件——人脸识别快速实现* L, }& H6 u9 C+ W
1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务
6 Z' ?) t( B4 v, s# T9 U! i2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,8 h# x6 T5 H+ E6 t
) i3 F' w5 i, w& x. |4 r采用如下接口对应联络到WIO Lite AI开发板,( a6 V: ]" n) w+ M& i" B
; h! j/ ?: ?3 t: l% ~& G) u
2 {. K C" W; ~8 w
使用调试夹子快速连接,就可以,如下图, m$ \- K D8 p* \: {9 k' ]' s8 `
Z% _* J/ R, e: n
在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI* e- `; O4 K, O& |2 T" i% p( }9 a
y# w9 y( Z& n D2 g
9 v/ v; @3 w+ @9 E$ R9 ]: U- p$ i2、创建模板项目,启动CubeIDE
3 ^/ x7 b* u; H. j4 u
& l* a5 Q/ \/ a. ?0 v3 s% t C可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。0 A! a9 O& L5 b, `, Q2 y
完成编译,执行下载,显示成功完成。
7 g( u( V* {0 c$ h" n
9 t) l- N" F2 i
" j, \6 G+ g. R9 M
3、运行模拟$ ^1 [9 q# k7 h6 l5 O5 o% O
上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,
2 @% d& F1 y. y+ b. H这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,
6 \) H# _- d7 ?: I# J# |7 i+ R2 u' g8 Y/ l
" u- ]. ]3 S" o+ Y移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
& l7 } i: m; N' W' M' q9 [& _; X( w" ^/ ]
1 F& a+ r+ p% D6 `这样快速监测成功。
1 o4 ^1 n4 [& V8 d, k4、人工智能实现的分析/ h5 Q2 s+ [1 ^4 S0 O! C
4.1 硬件平台的能力) j9 ?% \1 s+ \. k4 ~4 x* U
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
/ ^: q% C; {* W, U$ P- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽
/ A& }: j' \7 h5 w: ~! y* J
# A- i- \3 j, N: Q0 ]8 x; E% B% V! T; m- v
4.2 人脸识别的流程和库的支持7 K: c5 h1 E6 m* k
CubeAI的人脸识别是用如下层次实现
7 o) T. i5 ^4 P& Q
, @2 e# d1 M+ Z4 t; y
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下
h' ~; a: [ }5 k6 a
/ i- G! {) D+ }% z' L$ y, X9 n. `数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
d8 q0 H4 w- u9 d- u# N4.3 程序代码分析2 i/ t3 {6 [4 V8 a) H
首先定义图形数据的交换空间,是一个320x240的采样空间4 K! Y2 P' }; m# X' @8 D4 `6 |
- static Frame_TypeDef frame ={ .buffer = buffer,! U6 }( a- ~' I
- .length = 320 * 240 * 2,; P# ^" I- W, {6 `
- .width = 320,
# O) v# \9 e: m) Q# B+ b - .height = 240
$ _! B2 A( b& r3 Z$ v/ a - };
复制代码 主程序代码非常精简' }0 T$ f" W$ @$ Q2 ~6 e& j9 V
- & L b% W( h( E2 ]2 |7 Z
- int main(void)
/ S+ n8 U6 [; U: X2 z - {8 e( R+ S/ x3 K# }/ d4 i% d
- MPU_Config();4 }6 ?( O9 l, s. B4 `( G- ~
- SCB_EnableICache();3 U. w# ?( i' u9 X# ?+ b' ]
- SCB_EnableDCache();$ c/ V9 N6 v' O9 B. [3 t8 J) [
- HAL_Init();
) b3 s% U* E' ~: D4 I - SystemClock_Config(); P. ^5 e% d/ M/ [2 z9 j4 w; C( V: I
- " I: ?% K" {; |# P/ g( O
- /* Initialize all configured peripherals */
1 v& `; e) Y8 y! C3 X& d - MX_GPIO_Init();
, v' `0 r1 V0 z. D5 Z2 J% N - MX_USART3_UART_Init();$ z! K" J% e8 G- {; ]+ P% ?
- MX_LTDC_Init();
) J% }% x1 x8 r* `0 S& k5 q - MX_I2C4_Init();" ^3 ]- ]6 }5 O6 s' R
- MX_DMA_Init();0 }$ t$ F/ H: x8 B4 T ^
- MX_DCMI_Init();
' d( b. H- i( I- S4 N: W0 O( @6 C - MX_TIM2_Init();
) W! X! l5 c: I5 q2 x - MX_OCTOSPI1_Init();
9 Q- X$ w2 Z) p2 b - MX_CRC_Init();
+ }" Y& U' [5 w. S" S& b) g0 \ - LOG("here");
3 `# n( E& T/ b" M5 R - Psram_Init();+ ?) u a. |6 w
5 n* r. D( X7 ~% y- /*OV2640 Init*/
9 }! O/ l7 I8 ]$ ]0 y - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK, O9 T- m) q4 s8 x8 k* y
- OV2640_Init(&OV2640);
1 \* ~# f# }. H8 Q0 j! { - OV2640_ReadID(&(OV2640.ID));
+ M- x' A d' G* t, B - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);; |% ?8 q8 [8 N$ U4 l2 b
- OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.
# |$ G, }; a% h9 |6 L& ~ - OV2640_Flip();
, [* n! Y1 l. a' x" v! q - OV2640_Start(); //initial IPL and AI
- \! K; P' ?% a1 y% ^ - STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);+ |, }# C% t1 U
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */
' p2 v6 z$ {9 U( S& q! Y- F - __HAL_RCC_CRC_CLK_ENABLE();
& Y# m; ]6 `) \+ q7 x! d - aiInit();
* }! R& p. ~2 D5 U - frame_rgb565.data = frame.buffer; k8 b$ U; [8 ], ^
- 1 `5 O4 g7 ]0 L- r1 y @) _
- while (1)
b. `# ]9 m& l% E - {
# h# y) [8 ]0 y) a; @* v - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
5 V1 q' f1 M9 |% |- L - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);0 C- r" r8 f) c6 E
- 9 }" H+ y9 p! ?1 k8 {7 ^
- // rgb565 320*240*2 to grayscale 320*240
% B2 Y# j( A+ {, t+ e - if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {* w# F( [) T2 |$ m0 S7 F& a
- while(1);
], x' I$ D$ x6 \9 n; M$ [ - }4 p5 c) u3 j% Q% z% R) l8 e$ S. I0 u
- // grayscale 320*240 to grayscale 96x96x23 J% T# K/ M: b! e. N
- if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {/ r Q8 G: S+ i, f6 g. x/ G$ K& n% @
- while(1);+ Y9 ~4 L7 y9 X8 L; A/ J9 }2 U
- }: j4 D* K) i. A% I" v X/ J9 D
- 6 j$ r4 p8 t N$ l3 D" A
- //AI
6 M0 w5 v0 ~) Y/ S; U; d) u - aiRun(buffer_grayscale_resized, network_output);% H2 M; j. Z" @3 r
- postprocess(network_output);& |% o# i) [/ G. {2 j5 }
& d- S. |. }6 W5 }" a z0 e/ L- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
2 w* E0 U3 i) {/ a3 p - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);
, z8 J- o0 ]4 L, v% ~" c - & K0 e$ h- h' t# s* o: Y5 E
- }
- u: L# N! |; v9 d1 I - }
' B ^) ? [) K8 X% f3 w
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,
7 `1 S* S! ~0 ~4 _) _实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果 {( e* J; m" v# h" ]5 w9 A
; C! `4 j* {7 {( M
- aiRun(buffer_grayscale_resized, network_output);5 _' L* E* ~! ]( w8 b \' C6 s+ Q7 `
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,( k* t/ [1 @5 O. z
- void aiRun(ai_u8 *pIn, ai_u8 *pOut)! t' Z& }1 y( {4 p
- {8 t8 y: P" R' s5 M7 e" n3 b
- ai_i32 batch;
5 S" k5 \% F4 F1 k* K, A1 N3 j - ai_error err;$ N, t' ~4 c8 f$ ^
- & {+ `+ h2 M. I# ?
- /* 1 - Create the AI buffer IO handlers with the default definition *// \6 m4 U3 X5 m# Z1 s3 f, h
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;, V0 g5 a! O4 W) t- x4 n
- ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
$ Z- @, o/ T* V - & [9 |# X! y8 w0 K J* Z
- /* 2 - Update IO handlers with the data payload */! E1 S3 r! | [3 o4 _
- ai_input[0].n_batches = 1;& j% t% q# [- u$ v) a( ?% w1 @
- ai_input[0].data = AI_HANDLE_PTR(pIn);5 w# `7 [$ r. ?! y) @* N
- ai_output[0].n_batches = 1;& q! }+ p( g5 F% C k" q7 C! u4 a
- ai_output[0].data = AI_HANDLE_PTR(pOut);2 p f6 X. Z( D, r7 w j
' ^+ M5 z7 w6 l6 B$ |/ k- batch = ai_network_run(network, ai_input, ai_output);; C8 @1 F/ S H6 ^ ^
- if (batch != 1) {
4 V( a$ B. o: P7 G - err = ai_network_get_error(network);
" J& U# {! A$ V. N. P( R, \' d. d - printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);. q2 G3 v4 O8 `$ C# K
- Error_Handler();" O: q, E. k0 |2 z+ v
- }, [5 B0 U, g/ E7 y9 h- c2 j
- }
+ h3 c# I" H6 r) l/ j* c
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,
8 @: e! @) v. O$ w% h) K- ai_i32 ai_network_run(
# S. j* v) H* f3 Z$ C - ai_handle network, const ai_buffer* input, ai_buffer* output)
4 G0 s1 j( B3 S( [% K% j - {+ C, g# E& f3 L8 `, o
- return ai_platform_network_process(network, input, output);- h" o; c( [( p R# @+ }
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。( x* T6 K$ B" `2 s
# B+ b+ f8 a- N; V
5 小结
: K3 _, G" ^3 `7 ?, S8 q9 ^3 Z 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。9 l7 F: ~6 g- o! U9 v7 P
在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。
c$ N+ G6 B& {& M) f
5 k& v) A* n/ q: y7 A3 P
3 h4 \% \( X/ p5 M& r2 I1 ]
2 _1 `, ^4 N9 H: j
3 T! v ?% i1 {$ f5 |, @' ~( y! ~( J, m) S+ N; X* e T
) ?7 ? Z' d2 l1 Y$ \# R
/ t. v5 r; \2 r: G. L+ D4 X& }9 ~9 w) q+ n
0 b% J3 P% V/ o6 u: }& A
% A$ Y$ d, ^0 e& U. t, | |
' h* ^) q# Y8 ?0 p
大佬求源码
UP求驱动程序