Wio Lite AI视觉开发套件——人脸识别快速实现
! g- e9 c6 k5 P u) M- ~1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务% E' ?) ?% }/ F& {5 l9 \
2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,
' h* ~: q0 q/ P2 K( ^- p5 e; N
" w/ m( Q+ R0 N4 o5 q6 D采用如下接口对应联络到WIO Lite AI开发板,* e! f: p" u/ g, ^8 r% g+ _
4 Y) z2 y: p' c: x. m+ s; j5 J
/ c* Y! Q9 ]: s3 O( }2 _6 C: s
使用调试夹子快速连接,就可以,如下图,
8 N# }- Z0 W3 `* ?+ w
( s1 K# c5 M( Q" z5 l% n, ?在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI7 S; D; ~' s" T4 N1 f5 P+ c' a
) }% t' v; k4 Y+ o2 [
) d' K+ L! |9 ]: o
2、创建模板项目,启动CubeIDE
6 b; B2 P! t' }' H) P
6 a8 D2 Z6 {- Y8 ?- c, t& ~ s
可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。
% N$ U" H/ C) U9 }( X完成编译,执行下载,显示成功完成。% @; h/ c7 V% I! r/ \; Z& e4 N
" o5 e0 r. I8 l
) `; H Q4 W6 \. e: B
3、运行模拟/ r! _' o3 a7 o! z
上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,7 F: J) w- u+ n' \2 D- P
这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,
5 G- A0 U% s9 s! R( V3 ]- w& w2 Y9 m; h2 z
' C( D* A, D! h) b# `. h
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
1 \) X0 X! G0 i6 F6 s6 e" A. f9 h! e+ p# F
% F6 A/ q+ j9 H
这样快速监测成功。( d0 L, S: Q1 g/ B
4、人工智能实现的分析
: ~8 n4 S) ?3 f. H" R4 B8 S4.1 硬件平台的能力
' e) `) S& B4 e# X2 _! e4 UWIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,
. _7 H3 A0 C; ~2 N% A9 p3 ?: }- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽
* I2 p" @- Z, b N' k
* Z% N# ?3 C6 f: k! G+ L2 X; w+ U* [# W, P/ {6 N
4.2 人脸识别的流程和库的支持4 c5 u8 N. O$ ]" j
CubeAI的人脸识别是用如下层次实现
# w9 k! h+ I! t4 ^/ j4 O; G b9 R
8 w& s2 z: c7 _& U3 K6 Z R在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下8 T, |0 L& H! k* S! v1 @
' q0 D+ l- n4 o A3 u+ E* f
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
4 M. |8 c) K" J' h+ A6 y4.3 程序代码分析
5 j: H, K7 |9 U$ F$ m' I8 I首先定义图形数据的交换空间,是一个320x240的采样空间* `+ _4 \5 b! H
- static Frame_TypeDef frame ={ .buffer = buffer,
/ b4 X2 R* j3 R& e9 E5 k - .length = 320 * 240 * 2,
4 F( b6 z a- S( x/ r; ~- v - .width = 320,
; ]8 M1 e% O/ E - .height = 240
" ]9 i- \$ ~" ]# j, Q. v - };
复制代码 主程序代码非常精简$ C9 X/ u0 K5 D1 U: x+ [ s# K
- 4 @; \6 z5 A% y/ Q/ M/ S% w* \' n
- int main(void)
* ] V- F( ^% N - {
! A! T! O7 y' V0 _4 {# x# j - MPU_Config();: e3 H+ W& `5 m2 G; l' v( a# m
- SCB_EnableICache();, X, c5 h8 H9 x/ U$ ]) n
- SCB_EnableDCache();: @6 T0 s0 O+ c5 s% b
- HAL_Init();
5 D8 Z8 ~+ K. f, X3 } - SystemClock_Config();
; [5 ?) R X" a6 F: w( P" y% Q0 V
i* u6 B0 ?7 M- /* Initialize all configured peripherals */" A$ t( [" A0 x% b
- MX_GPIO_Init();# {7 W: A) J/ P: D3 {. j3 ?( ]
- MX_USART3_UART_Init();
- v4 h4 ^+ c5 ]% z. G1 F. p3 N' Y - MX_LTDC_Init();* d$ J! {9 h$ w' l* u
- MX_I2C4_Init();+ r y1 r* M d6 N) U9 E
- MX_DMA_Init();
3 v6 y# R3 o+ _: z: P - MX_DCMI_Init();0 E' }4 D4 R. ]' J5 l% {+ e2 ?
- MX_TIM2_Init();
* s2 L; {% s0 w - MX_OCTOSPI1_Init(); U* k# W' \. K5 x" ~7 P n. v
- MX_CRC_Init();$ r: g0 j( S; |: Z; c
- LOG("here");% z3 P. x) C% `1 w7 t8 j
- Psram_Init();
/ ]* b+ |0 G: v; `' V* P6 t M - & b5 g4 y1 C! |: y2 e0 p" C' p
- /*OV2640 Init*/1 y5 W3 G% j% C
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK
* H; Q* G! f7 y7 c - OV2640_Init(&OV2640);
" l9 g: @) f& i+ \" i2 _$ ~' O - OV2640_ReadID(&(OV2640.ID));
- j; Y9 p+ r) s: G! h1 y. L0 } - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);
/ q6 I$ k- j; ` - OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.% `2 @) e( l" r9 H2 ?7 Y. U
- OV2640_Flip();
* u* E8 z% x# v J" _+ L6 p - OV2640_Start(); //initial IPL and AI
4 c" ]! q1 @& O/ x3 x& w( H - STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);
5 U. u L0 N/ W9 M3 X- K - /* The STM32 CRC IP clock should be enabled to use the network runtime library */. F D: Z9 e5 m" J+ u# G; c
- __HAL_RCC_CRC_CLK_ENABLE();
1 X4 N4 J/ Y$ [9 T6 O, i7 _ - aiInit();: Y; }$ ^+ G. ~( ~: }0 i& m; y
- frame_rgb565.data = frame.buffer;
* _6 {; A' z$ g1 e9 y
. L w5 T+ ?$ p9 E1 |- while (1)" J# F; s Z% }" D. _
- {) q% z0 q H" @- d) u9 P( K4 R" Q
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
. s* p' D) M9 k - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);+ ^! h+ D) }. k
* i: ?$ Q* _4 ~- c9 T- // rgb565 320*240*2 to grayscale 320*240
# c. w8 I. j4 Z6 P+ f2 d' p/ V - if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {
3 ^3 l1 M5 S `6 `! n6 D - while(1);
% `& M$ }+ Y- d3 U - }
, G% ?8 i4 c: y8 ~ - // grayscale 320*240 to grayscale 96x96x2; j5 _3 J! L V6 ?. q$ L
- if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {& A/ l+ J7 ?9 F. ?
- while(1);
/ x4 ?. r6 E& x) q - }
$ u1 b/ ~+ c& Z0 p
: Z! n& C9 `$ Y5 H5 m) _% l& M- //AI e* S# M' G% g% p P
- aiRun(buffer_grayscale_resized, network_output);
5 o: z2 _- ]3 b2 S9 s4 p - postprocess(network_output);7 }1 _4 J4 x, b- R
- : {* C0 u/ M4 j3 L2 c0 t
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
. O/ w8 C* T- V - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);5 B7 `: F% l& ~" f0 b% C
. K# n3 C7 @+ ?& i8 F- }1 R4 v! d6 A) l# q3 q/ N# S
- }4 q6 s' o3 R' }& f% G* r( c
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,% `( @+ a% U& ?0 }' d7 ~
实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果
. i0 h5 N( U; d! o2 t0 N! U. i( h3 |+ \; B; X8 u5 l V9 G; e
- aiRun(buffer_grayscale_resized, network_output);+ I1 J' \2 w3 g+ Z6 W# S. C0 G5 w
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,
+ m3 f! R9 k* b* |8 R- void aiRun(ai_u8 *pIn, ai_u8 *pOut)
, o2 I! G$ p& i# m: ` - {6 _1 t2 \0 U7 q" l5 }5 K) T8 v
- ai_i32 batch;" V1 [3 d1 j4 v% }6 @6 }0 P+ w+ ?
- ai_error err;
- J% {' G& S$ u0 C - , L$ {8 t- f" \9 D4 _
- /* 1 - Create the AI buffer IO handlers with the default definition */. x3 h, D" `# t) }2 p, G: i
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;, \9 E; C* Z; H; l) k
- ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
- P, D( F# I/ i; Q. ~
7 H4 b3 d! L" e. w5 z- X- /* 2 - Update IO handlers with the data payload */
: }/ O( h8 U4 E6 ?9 Q* _0 s# z. ~) c - ai_input[0].n_batches = 1;3 _/ a/ y8 J! A" ^8 {7 `' s6 H! k( V
- ai_input[0].data = AI_HANDLE_PTR(pIn);
8 @, w0 {6 ~4 }, G" q - ai_output[0].n_batches = 1;2 U1 f9 U0 W q7 m% c
- ai_output[0].data = AI_HANDLE_PTR(pOut);* o3 C, ~/ l2 s) o9 O
- 1 @9 E, g/ k( Y7 u F v
- batch = ai_network_run(network, ai_input, ai_output);5 K. t k. `/ L
- if (batch != 1) {2 w# B- A9 Q# J S7 ~3 X# F
- err = ai_network_get_error(network);' v" v: ~$ [ ]1 z
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);
! G( x+ m0 D% \2 N - Error_Handler();
8 n4 j1 Q6 w4 z) F' `5 a3 p: }" b - }
+ G' ^2 R- g9 W# v2 B1 r/ {4 Z - }0 q: z/ X/ }- z8 M
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,1 \6 m/ ^4 C. }; I9 P8 ?
- ai_i32 ai_network_run(
U* j) ^( F4 f, C) {6 f' X! Y - ai_handle network, const ai_buffer* input, ai_buffer* output)! W* }$ Y: k. M( C
- {
0 C# q9 U# C: L/ {; X - return ai_platform_network_process(network, input, output); i# T0 c. S) r4 w* ]. x
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。% j5 C- V& A2 n+ P
, h( N; ]7 g& j6 X$ N! E. D
5 小结! N! z6 B @/ ]% P: T/ ], l
基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。
& n% d$ L2 w! t! P$ A 在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。) F3 \0 B& X; m% J' v4 x0 ?
( e1 w2 }! N9 B9 j$ D. N2 F: l/ K1 P$ Q) m; ]; m p
$ W- v$ W( r3 U& U! y
5 }* F: j. q( {" T. ^* q* g* N2 {1 t3 y+ N
8 o3 n' k6 C+ S/ T2 X& F$ ~2 y
8 H2 g$ i! L- E4 d. Z
( r: q- o) X- W% N. o1 i' Y
2 _( a, m' l$ o/ @4 G# ^) f9 Q5 m: B9 U: A7 p' T/ p' S8 Z
|
* i0 y8 ^7 {4 |
大佬求源码
UP求驱动程序