Wio Lite AI视觉开发套件——人脸识别快速实现
q% \% E e, Q2 n; p* Z" Q s1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务
* ~9 n+ g- X8 b( l3 ] q2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,8 V7 S1 u2 g( U" {- c' n
% B" `1 O* A6 @
采用如下接口对应联络到WIO Lite AI开发板,
# J( a f! e; [1 y+ ?: f1 A D+ R( |: L3 l; }1 x* e
% o5 L$ z. ~: i使用调试夹子快速连接,就可以,如下图,
* L0 R1 y6 f K- U
4 s7 a5 ]5 [' R) V$ x- R9 W# u
在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
4 v6 {: a* r! B Y; @' G9 ?! ^8 b& E! ]1 @( K
/ J6 t1 A. O; j- Z1 r/ k2、创建模板项目,启动CubeIDE9 ^" J. s$ {" k3 F
2 e' {3 l- f4 Y$ o. A% ]: O可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。1 W3 }- r$ f4 ^, o3 T) m: q
完成编译,执行下载,显示成功完成。
- E% T f5 p N; ^" n3 C7 j: p; ~% I' m( k7 Y7 V# }! @ r. U
4 ^. O& u# z3 r2 f" J8 }3 f B3、运行模拟2 m8 {& w4 |" b
上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,5 z3 J) W: b0 G& q9 s9 y
这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,) C/ |8 ?* r q& A; A6 H/ y
3 j. m: l" G) t" _# ^! a5 Y- E, [
+ `9 D0 v2 O2 P$ Z& y& ^! R% M
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。2 J: g. B" a% n) x
/ l5 P4 W7 S# q' p
- n# k0 D1 \2 [1 G. \% }
这样快速监测成功。
1 C& r6 |. T; `6 p+ |4 F4、人工智能实现的分析. b; Z) }( [: r, U9 L' G- R
4.1 硬件平台的能力
; K3 g a2 I6 L2 i; o6 JWIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
$ _' N& S3 o1 L) E; ^$ h- D2 @$ ?- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽! M: s7 f) o J6 \# |5 d
" A- `5 j: c: K
$ y7 O$ I5 R6 N1 B
4.2 人脸识别的流程和库的支持
% Q* M, i; M, g, B1 r& i% qCubeAI的人脸识别是用如下层次实现' C# F) u- \* u" ?- ^
4 z. P/ _# @2 a! K4 i在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下( a! L' G5 g0 `( t
% Q0 c* Q6 y: p2 b2 y" F, O% d
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
7 p/ T% B. G4 W0 c' G4.3 程序代码分析
?9 I4 i% c( y4 r首先定义图形数据的交换空间,是一个320x240的采样空间9 v& {# G1 V k) ^ l
- static Frame_TypeDef frame ={ .buffer = buffer,
3 l7 @6 O' y9 x. @6 ` | - .length = 320 * 240 * 2,
! y/ m% t, p7 `* ~) m8 ~! G; j( m' A - .width = 320,' k* U/ p8 S5 m9 \9 Q3 A
- .height = 240
4 k, M" U, @ g; m7 K. Q - };
复制代码 主程序代码非常精简
; @. M6 F% J2 ^4 E& }2 J$ a* o
# I6 t$ ?0 f- p- r9 w; w4 Y: s- int main(void)8 e5 T1 g/ A5 p) p" h* D
- {: H8 n0 ?: V* w* A7 u
- MPU_Config();
# w9 b5 r$ I/ o( `) a - SCB_EnableICache();" k1 J5 |( |+ h" d* S) j
- SCB_EnableDCache();7 ^2 Z. f! A9 z: I% ?2 Q) ?) ?
- HAL_Init();
0 h [8 u m7 S3 h0 i: | - SystemClock_Config();
! Y, V1 P" X/ W$ B! w0 I7 [- v
' x- M' |* s6 k5 G, W6 x" n' t- Y- /* Initialize all configured peripherals */
' ~% ?* K/ d: [8 O4 Y' U6 r% N7 [" p - MX_GPIO_Init();9 j2 A9 {1 A, }: F7 P
- MX_USART3_UART_Init();# S; ^1 F# ^' z5 v6 ~
- MX_LTDC_Init();
; h7 H- S" v1 Q6 ^' o, m* O3 e0 | - MX_I2C4_Init();
) L) S8 d: w; f% i# T+ n - MX_DMA_Init();3 p7 c% e1 g; C
- MX_DCMI_Init();
# q0 {& k2 @3 Z3 {& }/ |$ n1 N - MX_TIM2_Init();
# D0 X/ f+ ?: N, _5 e - MX_OCTOSPI1_Init();0 s) P& H' ?0 M& b" @' c% }/ {7 `9 o
- MX_CRC_Init();
( \) |! a! J2 H" k4 ]7 X. y: m - LOG("here");: H& ^" E3 M& V
- Psram_Init(); F/ U, u, g" X% O5 U
- 1 q% v8 F: P% v% W6 R! d
- /*OV2640 Init*/# l: A+ A k; j* y5 x. P
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK' k2 s- X4 F `) f! W
- OV2640_Init(&OV2640);3 I* \; V$ `- A' ^6 l
- OV2640_ReadID(&(OV2640.ID));
( y9 s' D+ F* a- C; r' c Q" R# T - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);* a0 [7 T7 a0 i8 l$ Q" r
- OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.
* X4 X1 _; }) W& z2 ]1 o& A n - OV2640_Flip();
9 M8 J8 o. V. u# O5 Z! \$ I. _0 B - OV2640_Start(); //initial IPL and AI: f" c. z2 b# s% A2 J! s
- STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);
& D a- M5 h' }* } - /* The STM32 CRC IP clock should be enabled to use the network runtime library */; t6 R& [) ?" f0 {4 |% Z0 @2 V' h
- __HAL_RCC_CRC_CLK_ENABLE();& {7 p: v; R0 y7 K8 c) V4 _
- aiInit();
7 |' R( F/ _0 t" w% {) G9 g, n - frame_rgb565.data = frame.buffer;
- J7 n1 o# a+ X- p' D4 V S
: C' [/ q1 n, F) o- while (1)# h/ ]! W# w& N2 m5 @
- {
' d& F7 {4 S+ y7 a, K! Y' i2 A) h! T - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);) C6 r; I0 V' \
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
$ ?& ~0 v q" \) S; x - 9 C( W: s) L5 y
- // rgb565 320*240*2 to grayscale 320*240
0 @0 U) {) v6 @- b6 E7 v - if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {' Z3 d0 K: C5 t; a! G( J+ q1 t# b
- while(1);
& m4 e; o4 }) u+ O+ o) M - }) N- y$ ^' J8 Q" p4 c8 R' y7 {
- // grayscale 320*240 to grayscale 96x96x2
: R) H8 m/ c0 C4 G - if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {
: q. t" `( u$ A: |* [ O3 O - while(1);
9 V' X+ @" f9 Z) A6 ]1 f3 }# w2 ]8 T% N* G - }
& t' m3 z' y/ M, `- X% H - 9 _+ b2 P. s! H, G A1 `
- //AI( w2 r x; Z, B- W
- aiRun(buffer_grayscale_resized, network_output);. |. r O6 K/ J+ D
- postprocess(network_output);
0 L- M- s9 j' n& x1 z; N
$ y( X8 Z/ f# |3 J; x5 d: A- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
& g4 N9 e7 f6 K% d+ n9 ^ - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);
, N% ?, j8 k2 Q! V" f% L5 \* r
( F( w/ o3 U) H# \; c; s- }
7 a- L0 u! t. e5 v - }
+ G9 \! c* @- E! p3 z4 K
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,
$ t' Y) s4 I9 }" H实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果1 O# H$ ~( Q- b
! c" H1 S% J- P- R" G% `/ z O- aiRun(buffer_grayscale_resized, network_output);: N. ~3 M$ O0 }
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,$ e& z2 Y9 U# ` ^
- void aiRun(ai_u8 *pIn, ai_u8 *pOut)6 V% B% v9 N9 A/ O7 Z+ C! J+ Y4 C
- {, b. O2 ]$ t0 g1 s" u
- ai_i32 batch;
' g* K( y! G9 G) G2 k - ai_error err;- o6 B& Q$ f) ]1 B. o2 @( ]
2 N& p' f# x& E- /* 1 - Create the AI buffer IO handlers with the default definition */1 S. P$ B2 m, B; z3 q
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;
! Q% H7 I3 W' w: U$ M8 L4 ^; d - ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;4 |; a6 P8 J3 G
B( k+ Z( V5 T0 t, o6 v- /* 2 - Update IO handlers with the data payload */* S. G% b: g% t8 r9 \: R/ M# I
- ai_input[0].n_batches = 1;. y# T+ V w; T4 H
- ai_input[0].data = AI_HANDLE_PTR(pIn);/ Q* Z# ?- O$ V7 q
- ai_output[0].n_batches = 1;
7 }8 y: f0 _2 A% V7 g- ? - ai_output[0].data = AI_HANDLE_PTR(pOut);
U! j ~4 {6 n7 m- s/ L - 6 @( v! o! P- h: o- h
- batch = ai_network_run(network, ai_input, ai_output);) }; G( h# e9 N t5 |* S
- if (batch != 1) {
: K8 r# J9 \5 K: o9 \8 n! F( x. w - err = ai_network_get_error(network);
" f$ P+ D% O4 ^0 @1 E* u0 z - printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);
& U6 C1 H7 ?1 E; {% t; I; F - Error_Handler();: I6 u: a" k2 \+ {! I8 Q/ G( F
- }
0 V5 W3 T$ I8 ~4 D$ ]" v9 n - }
6 R# q- ?" Z$ X0 U8 E
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,# ?% h! _* r% J: g( p1 e O
- ai_i32 ai_network_run(5 _4 Q4 r7 t- B- p" m! `
- ai_handle network, const ai_buffer* input, ai_buffer* output)2 k0 \) T# C4 L X6 `5 ^
- {& ~. {/ E* o1 S. v$ }4 u
- return ai_platform_network_process(network, input, output);
) r) A! C; Y* G# }. k: q - }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。7 N$ t: [3 V: \4 u% K" ~
5 {6 i1 T4 q1 g% ?+ p+ F+ ^5 小结
8 G2 N! _$ m) B" | 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。; s- T' F# I* I# g
在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。- {: |# y/ r7 q8 q! O
% \. S' ^- T, G: g8 h. I8 s
7 Y8 s) m; b) q6 L* ^+ ?
1 M* ]4 ]3 V% B/ s' G! f$ t
4 ?: \, M6 S1 I& F
9 N2 |' \; T# C
( k$ U. H; ~, c- ]$ t6 f
3 T D0 I. g& s! K: b+ U6 a' L
2 @/ B. d0 }1 ?( n* b a' w- I/ k f# |$ w" R
- j% A" C) `6 g0 D
|
5 c+ K% F. L) s* `- Z9 |1 k7 ?
大佬求源码
UP求驱动程序