Wio Lite AI视觉开发套件——人脸识别快速实现# Q: T+ R8 F- u0 K) X5 C( U
1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务
! t; p. i! Y, }5 z& A3 ^2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,1 D3 X% S7 N! @! G
. m; M' g/ Q* r) I" Z
采用如下接口对应联络到WIO Lite AI开发板,
8 T+ ~6 a, _9 u) Z
$ T* v4 ]1 H$ B
. l4 z5 z+ V+ h8 f8 R9 i. P
使用调试夹子快速连接,就可以,如下图, i0 O% [- }$ C% {8 Y2 T
( I6 ]% }8 M. L1 X在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
9 c/ P3 y7 U2 o% m& B Z7 d5 r4 S0 `. T0 y
6 k- _# e) v+ \! r, p
2、创建模板项目,启动CubeIDE
0 B, l3 ]4 ~0 }) A- C
2 W5 p, f) _/ x可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。$ Z, k4 y2 r5 [/ B @0 @, P
完成编译,执行下载,显示成功完成。/ x8 ^3 i& D: C+ S
- q0 e, m6 q4 d# h4 d2 I: m# U
7 R) \8 t4 l- D- H: W% R+ @$ E" ?7 t3、运行模拟
, `' T, H1 j. Y1 D' C上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,
" `, \. b# p* M0 x7 h这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,
, x* j# C( }; u/ u' v' }# G% f, @
6 A2 S# ^. h7 T0 v! Y: }% ~
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
" P V7 k/ I8 k) b
$ S8 A0 T; j [3 A+ a
9 J: b0 `$ M7 a! n! i
这样快速监测成功。
% Q7 D" S+ [3 B/ ~4、人工智能实现的分析3 I3 ]$ S; l. K$ w' Q1 u6 C
4.1 硬件平台的能力2 _! N$ ]. Y$ f" y7 e2 r D
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
& ]; I& V `( h2 \9 S, q5 r- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽
" J0 M# K8 P, I8 q( c: E9 Y5 {
/ X; u* l9 `, n) I6 ^0 _. O7 @" X: K, \! C1 e& D
4.2 人脸识别的流程和库的支持0 d, c" m: A) o7 M' n
CubeAI的人脸识别是用如下层次实现! Q$ H: ~- r- c# n9 T
1 B( y$ T& f/ Q U3 l在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下
* `$ Y% F# ` u% c0 r
$ p+ v) t" V5 e. e7 ?* z数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
: W! [1 ^0 x0 D2 ^3 X4.3 程序代码分析# V8 B* s- G7 @' D# m$ c
首先定义图形数据的交换空间,是一个320x240的采样空间
. M9 s8 c% Q0 `6 [) m- static Frame_TypeDef frame ={ .buffer = buffer,
6 Q% w8 d" E9 w8 e' x+ } - .length = 320 * 240 * 2,$ C: s4 Z$ [% C' H" j
- .width = 320,
; o2 Z0 _! G m0 @5 | - .height = 2401 e* \, l. ?# {1 j$ W' f6 _1 ~% y
- };
复制代码 主程序代码非常精简
8 }" j. M. {% g
- h" I! v4 a2 k2 O- int main(void). ?- L. \5 H" o
- {9 c$ I5 Y8 R4 U) r% {4 a) v
- MPU_Config();/ } ~4 O: y8 P
- SCB_EnableICache();
2 H; e: ?! T+ Y. o( A - SCB_EnableDCache();/ q6 o$ l# [& d I
- HAL_Init();; L+ k' ?% I( R6 o0 P8 w
- SystemClock_Config();
1 H8 Y s1 u5 X/ T
; `6 K( `7 k& B. T P: W/ ^% v% |- /* Initialize all configured peripherals */- a6 B7 R/ ]# ]* [
- MX_GPIO_Init();
5 }) g7 { M' E, f% c: ^* `2 Q - MX_USART3_UART_Init();
9 O7 |4 I; Z) L) T) _ - MX_LTDC_Init();) Z5 e1 l4 X+ q! v
- MX_I2C4_Init();6 J& P" v3 Y" F, f9 o3 Z* k' b
- MX_DMA_Init();) ]4 I& s. J0 b! ^, F& D
- MX_DCMI_Init();/ C- \1 |' ]3 b) n- \: ~5 ^* R
- MX_TIM2_Init();
" S7 W, _, U; W4 v K - MX_OCTOSPI1_Init();
9 r" T8 y8 ^5 x, z0 [' T - MX_CRC_Init();
$ b! `" b$ J" r5 l! E - LOG("here");0 p5 S4 `4 X* s3 W. h/ v
- Psram_Init();: x% C: {% T) R" M; y d
- 9 P; ?8 a% I; C8 x
- /*OV2640 Init*/# X+ s, @+ i9 s& s' S6 ]
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK2 I3 Y; p C- S0 x% _
- OV2640_Init(&OV2640);0 |& X: C4 L/ r0 w
- OV2640_ReadID(&(OV2640.ID));
' } h) m8 I; m1 s+ ~ - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);
: n( M) n2 |% z; }# t# D - OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.- C Z* b1 o4 U7 X6 u; j' t
- OV2640_Flip();' h0 g+ o0 o- R' F: g6 v J3 o; ?6 V
- OV2640_Start(); //initial IPL and AI; U8 L, i# R: X y% C- O# h9 C A
- STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);5 f' w- ?( n5 [1 p$ D2 c
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */- V* x* {# V! F( |: W& w
- __HAL_RCC_CRC_CLK_ENABLE();
* D# g8 L! _8 j% m9 H7 U P - aiInit();) d% G- f+ G$ P8 Y. ^( v) s; q1 f
- frame_rgb565.data = frame.buffer;3 l8 ?) j# V6 C4 \! j
+ C& B& |/ y7 C- while (1)
9 ?, f- X6 H4 A# q* J- B - {
5 W- y" t6 q6 E- U5 s3 T" o - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);- [" u0 d a. O$ p3 w& `8 w$ B
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);
' ^: ^2 j) p# ?/ `. ?
' T2 D" S' e$ y0 o- // rgb565 320*240*2 to grayscale 320*240# ?9 R4 U" J) {: I1 h+ ]
- if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {
/ G3 k, S$ D* h. ^; h1 M# G - while(1);
: {7 g- ` b6 {8 }: y' {( e8 U - }7 Y. e2 `" p9 B# f ], i
- // grayscale 320*240 to grayscale 96x96x25 r7 R, Y' M+ |: J% C
- if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {
" N2 B1 t" k* n6 z& H* Q( m6 m - while(1);
5 h2 ~8 R$ B- U - }' M, z" o% `! l. o
- . A3 X; P5 W I$ e0 S7 P7 i
- //AI( g1 S5 {# W5 S4 _! ^
- aiRun(buffer_grayscale_resized, network_output);7 y( \: ]" p* j! b6 O
- postprocess(network_output); j( N `! [+ K
- * Q$ a2 P0 f/ L! ^4 b
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);9 D5 E$ C! w& y/ F( F9 A0 _9 a: {
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);9 ?4 q3 i- I. N* p! r
0 x% Q8 d F, O1 Y' F x- }0 U% Y0 A+ G) E% ]
- }
1 B. r2 D" Q( M! [( ?
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,* Q5 y: ?) x5 A% ~% N! F
实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果
- t6 q( B/ J) B) A# o O/ x' z. K8 B
- aiRun(buffer_grayscale_resized, network_output);- H% Z. E/ p0 o4 ^& _6 `
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,, k/ e7 n Y' P2 n1 G
- void aiRun(ai_u8 *pIn, ai_u8 *pOut)0 f9 a2 _: e$ C* r" q9 F
- {8 p! M7 A* D9 ~ _# d( b/ O& ?
- ai_i32 batch;
; C F5 e8 B! G; s2 ^; S - ai_error err;( @' d( K" C2 c7 `/ u
9 N- h0 \: [% E% }5 F1 x* `1 z- /* 1 - Create the AI buffer IO handlers with the default definition */
0 L8 P+ m! i. L. Y- `! k2 U' Q% D - ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;
5 e8 j! S X, X7 Z) J4 S - ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;$ T9 D, o1 L* p" ]! P6 {% J2 u+ h" n9 ^
- 1 E0 I4 W) S# g2 Q, A
- /* 2 - Update IO handlers with the data payload */1 M4 b* K3 Q1 l) z) _
- ai_input[0].n_batches = 1;# h9 u" F2 v f1 U: g
- ai_input[0].data = AI_HANDLE_PTR(pIn);
: {- G0 c" g3 Y- l U1 u" f5 O - ai_output[0].n_batches = 1;
. e- t2 w$ O6 G$ R* q/ Z - ai_output[0].data = AI_HANDLE_PTR(pOut);( G* E; C5 t3 j. y4 P/ D3 f6 u0 d
; @+ ^* R1 U* ?- batch = ai_network_run(network, ai_input, ai_output);
8 [& y3 L \( ]1 Z7 _" O - if (batch != 1) {
# C! A; Q8 p9 A2 Z - err = ai_network_get_error(network);& n- y' h6 b/ A7 z. _" k& j
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);
' W- l6 d! c+ }, A, u - Error_Handler();' Z/ t8 b. F. e& a: V0 [- b
- }
; b( ]) m" O/ s4 y2 @4 x+ ^ - }& z& `; ^& x/ v7 k# e" K
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,
E5 L% o# d% u, E ]- ai_i32 ai_network_run(
0 _+ `6 M' ?1 c1 p4 [ r - ai_handle network, const ai_buffer* input, ai_buffer* output)
1 S" c( j# O+ Z. N$ H - {
0 F6 ~) w; Q0 }: f - return ai_platform_network_process(network, input, output);
. ^0 t9 g; m) P! j! K - }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。0 ~/ c/ s4 `& l, Y3 U" H2 C4 W
, H7 q! ^, t2 p' n2 [8 |
5 小结
4 G! p# G% H% x Q" S- [ 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。: P& d& ?- H; g5 O
在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。
1 e% _3 F8 }/ H2 Z9 A( f- q5 L$ S. e4 Y/ X1 h5 g
2 G" l6 f, ~+ Z9 C3 E3 L: V% R2 O: E8 v9 P* b! T
" ^- r9 L4 J* @ }( ~6 x
& t( R( \3 @/ j# ?
e. `% `& c) A, F4 C @6 b7 I. O- `. i$ K
4 V1 C' n9 O/ @4 I$ |5 d
$ w" u% L5 a9 y" m
3 i9 O- W- `" F7 ~" x/ h8 n( r. A |
5 C+ }; W3 K- G
大佬求源码
UP求驱动程序