Wio Lite AI视觉开发套件——人脸识别快速实现
! B0 p5 l6 v% H5 y' e1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务" i% C+ L; ?2 ?0 y" K5 ~- C
2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接," F r7 W8 G4 o' _
1 H) E7 p: s6 o! {) k; z采用如下接口对应联络到WIO Lite AI开发板,
6 D, g* I1 [; k3 ~& K9 B, s9 @ Y* r$ F* ]1 m @8 C4 f
+ R) _5 i% i' P* j使用调试夹子快速连接,就可以,如下图,
0 ~' x7 X- J. I. w9 y$ Z
# ` K0 ]2 O( n
在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
$ S. [+ h0 Z. r" g
. w `9 |# ], ]6 c3 y* p- y3 G1 k/ I1 z ~
+ v0 l8 D/ R. k' m8 L2、创建模板项目,启动CubeIDE
! K! b- w9 Z$ ?3 _
9 V9 {5 L6 @# k
可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。0 N7 U8 {4 t$ y" I9 h) |/ R7 k' _
完成编译,执行下载,显示成功完成。
% A% \5 @2 C5 L- e) L) @
S+ Z7 f( n# T/ H" J
2 {/ v& B* N; A: p# G, {' k" i
3、运行模拟" @. | ?- T. `% G% k. e
上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,
) T0 `1 N7 N# c这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,/ g5 D, |6 X9 Y' `4 j3 H8 ~
8 x. V8 A% t* S, S! b, Z) g; C6 M
" \# M) K. C, K& b1 N
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
" O$ J' P+ `& g
. Q8 a8 t8 ^1 U' S4 E; \
: t8 L6 a. z6 I# t& u" f! Q5 [& ?这样快速监测成功。" Q4 r. B7 h. y- q1 e# k
4、人工智能实现的分析
9 S+ i( P. z( J5 j4.1 硬件平台的能力0 x; ~! ~( w9 w8 n# ?- k' O" l
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,/ v p+ n$ v% n6 j* O
- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽) r0 R8 i$ q* o1 x. H
% k- c/ u# m7 Z* N. x' F; O
8 Z& _! X) j+ M4.2 人脸识别的流程和库的支持5 i# [- t# J% l/ W2 d) ?# m8 t
CubeAI的人脸识别是用如下层次实现
, x9 |" ]$ e _+ P( e/ L% K
! x; Q* f* V! K% R q
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下0 ?+ p+ u( _% ^8 |+ {
7 C) k6 h. ~0 l! Q8 D! G' D0 l
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
7 K" Y* P) x% _! J1 y$ n% o; r4.3 程序代码分析: M" Z" t, L6 z6 T. H: S, D
首先定义图形数据的交换空间,是一个320x240的采样空间
# M' T) A' k' m- static Frame_TypeDef frame ={ .buffer = buffer,
) N* `7 H+ _- t$ Y9 ` - .length = 320 * 240 * 2,' c7 x0 \8 Q& _7 z
- .width = 320,
% v( m; \, R$ }% U" ~; H - .height = 240
8 j: v, r) s! n5 H7 i9 E - };
复制代码 主程序代码非常精简
+ r- R/ }2 n' Q- o. g& l3 W4 x; y
- int main(void)) n6 ~4 y1 K" Y2 C3 g
- {; B" A& G j, r5 v3 _. V- c
- MPU_Config(); o2 s: f4 [ T) ]
- SCB_EnableICache();
" ~+ z: w$ k% r4 {/ b! S/ L) O# ` - SCB_EnableDCache();) N; T8 P P$ N/ Q/ A4 }
- HAL_Init();' B% x- k5 Q1 e5 @
- SystemClock_Config();$ P% d. U# M: @; v
6 M8 ?8 z! @% F$ v8 C" p' w `- /* Initialize all configured peripherals */1 } q. Z% v2 J/ I' O! H
- MX_GPIO_Init();$ W) A2 b* M0 `5 X3 B
- MX_USART3_UART_Init();, B$ D* G2 |, P
- MX_LTDC_Init();4 ~% z+ k( A! H! |1 k+ K
- MX_I2C4_Init();$ m. h% n3 G8 G L
- MX_DMA_Init();
6 F R* y0 V" E* \/ J- y - MX_DCMI_Init();! j) }. G6 U+ \6 q
- MX_TIM2_Init();: |7 Q8 _+ f, S# r3 [' c1 `7 O; R
- MX_OCTOSPI1_Init();+ ^- T' c& G0 {& P4 v
- MX_CRC_Init();$ `% F- w! v2 ]2 \" S5 L. Q4 G
- LOG("here");
( g/ ?! ~- F r) w5 p - Psram_Init();0 Z5 S+ d I$ f8 x2 g: h
- ! |. F' F4 _+ S7 w
- /*OV2640 Init*/! ^0 \( G# ~0 M0 k) D
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK
' @" y* K* m" T: t ~& ^ - OV2640_Init(&OV2640);
; b2 z8 _6 R1 M, S3 P - OV2640_ReadID(&(OV2640.ID));
! H- S9 |7 i5 H: V) v - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);6 Z) P4 h V3 |) ]$ x
- OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.
% {2 Z/ x/ k) a& k6 Z4 o - OV2640_Flip();
' b& h& w/ c4 J- F1 m$ ? - OV2640_Start(); //initial IPL and AI0 B8 ~+ E& O ^1 t) ?$ D' P
- STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);$ }/ P7 E3 m6 n, F9 n, H& |5 U
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */
: ~3 L% ?! C7 G1 N4 N - __HAL_RCC_CRC_CLK_ENABLE(); W0 H. t* O$ Z" u
- aiInit();
9 _+ M; r& L" b! Z! o' }8 a) n8 E - frame_rgb565.data = frame.buffer;
' p; B- e6 @! J! A4 Z4 [) j& g
9 N2 ]0 ^) b% d- while (1)
8 d, _9 f) b% @! a! i# z& [ - {$ l# L# l% k+ B4 ~7 W
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);5 G. m, n* Q4 C6 y6 \
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
. d/ W5 ~) ]/ \0 Q0 }/ }* n) U) q, l1 T - 4 v6 q8 a; {5 }: p( q6 _
- // rgb565 320*240*2 to grayscale 320*240
- T4 \0 t+ W$ W* d! |- D - if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {
O" `& o+ o+ r7 \& k& p - while(1);0 H9 \- E- y0 \2 v/ n1 W0 u
- } C2 n9 c7 q H
- // grayscale 320*240 to grayscale 96x96x2
4 Q: h' z% n3 i0 }$ Z: T7 o" ~ - if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {
. |; Q( {) H/ V& a; m5 u - while(1);$ Y f# I5 R1 {" t& T
- }
% V! k$ ^/ V" ?: z* H' n8 F% [ - 6 v$ F* c. e' W* U- p' t3 Q
- //AI
7 H7 B2 R, Y) ~& d$ f% T - aiRun(buffer_grayscale_resized, network_output);
) w+ X* @: X: G! v - postprocess(network_output);" ]9 j7 _5 R. M/ Q7 B2 d$ D' u8 K$ @
N7 Y/ [7 ]5 z: M( v- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);4 J) I& i! F8 k. h0 \
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);
% B8 V0 }' Y5 J$ k, u7 u& p
5 G! v5 Z" v8 _# `, J- }5 x' O; Z0 E/ S. v/ s3 M/ Y
- }
9 g' h/ p# q* h; x
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,
+ Y, A" a7 @) H! v实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果
- t. d% S" V+ Q" H, u! F E
1 V j( v) y, S% I6 b1 |- aiRun(buffer_grayscale_resized, network_output);
5 p$ W( I: a/ T m* \# }+ s9 _7 p7 u- K - postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,4 Q5 Z) {) k' p* x
- void aiRun(ai_u8 *pIn, ai_u8 *pOut)" B2 ], X+ [% T; ?1 J6 b1 J& f2 F
- {
S8 K3 Q. E4 a" s2 I" v n - ai_i32 batch;
; l9 M4 U$ Y# W4 R1 q: g; s0 w - ai_error err;
5 K5 w) @) Q9 a; x7 k4 k a
6 b7 y9 F6 Q/ }9 P' n5 J. ?- /* 1 - Create the AI buffer IO handlers with the default definition */
C. L+ U3 t) q B7 w* J, p: ` - ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;. q' |. B* u% L$ \
- ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;! A2 ?+ d6 K1 E
1 n. F! |' N7 l1 L* x8 J- /* 2 - Update IO handlers with the data payload */7 E" j$ a$ x& C& Y" P
- ai_input[0].n_batches = 1;5 e# N* H. A* j6 b: J7 {
- ai_input[0].data = AI_HANDLE_PTR(pIn);! [- P0 p5 O4 A6 ]2 L% E
- ai_output[0].n_batches = 1;+ V, u5 T2 |5 p( P7 o. v0 ^
- ai_output[0].data = AI_HANDLE_PTR(pOut);" [( W( D3 Y( t) A6 f1 ^
( @2 ^% C/ U1 g- |- G- batch = ai_network_run(network, ai_input, ai_output);
4 [! E7 L% T1 M" p2 Z; d2 u - if (batch != 1) {: j, r+ u+ G, ]8 W
- err = ai_network_get_error(network);
; ]; x4 {2 d: p - printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);8 m. c' t9 G/ J7 N% M6 l$ w
- Error_Handler();1 m* K; A* u+ }( v) ]
- }
/ J7 }/ \5 D5 [7 b0 w - }
5 Z) @, x6 e) x1 e
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,* ^. P \1 F% E( E6 {7 `
- ai_i32 ai_network_run(
. a% U. O2 T- R2 l% T8 Z5 [* J - ai_handle network, const ai_buffer* input, ai_buffer* output)) x- F: k0 l' ~5 x% }$ R. k
- {: s9 d0 A! K, r; E6 l, y
- return ai_platform_network_process(network, input, output);# j. W% {+ Z3 h9 Z) J. y3 b) F
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。
: h9 G) i7 D' M! Z6 {2 c* g/ K7 a* p0 [+ y7 d/ X1 P
5 小结
& [# b7 O' ~0 d: G) c F 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。
! ^: V* L3 k- o! d1 [ 在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。& `( O% M& z5 J H/ y6 `
$ a# i# }9 @4 K( y
1 A3 C' F- p' H, p5 ~6 Z7 i' U. y
( _. X1 e5 V; }- R, }) b7 `! ?( b# ~9 A3 a7 O! G& I+ Q2 T
2 ]3 o; F/ d( b4 a0 j- k, P3 c* Z) j( q4 V, \
2 ^/ M9 z9 `2 q9 ^$ s
8 i7 j E* Y4 {8 ]# N
8 ]" F3 M# S4 o0 L3 V) u. P0 n4 k5 Z" _5 J: w/ G; `' r
|
大佬求源码
UP求驱动程序