Wio Lite AI视觉开发套件——人脸识别快速实现% Y' B z5 n" R* U* t$ B
1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务
! u, p9 [$ |+ F7 E2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,, c) x. P6 Z) ^3 k# L9 |
+ o5 F, o" {0 G! E9 @* `6 ]采用如下接口对应联络到WIO Lite AI开发板,0 r, i; d! F2 U+ R, T( w1 \0 e
( b9 D9 h2 ?/ w5 K7 P+ p; Y" D. m
5 I4 Y2 [* b$ b1 S- l' }5 c5 {/ h* i0 _
使用调试夹子快速连接,就可以,如下图,
( d5 T# U- E# x8 c7 z
! Y, q' p6 O& E3 E4 l9 K; o" t3 O4 ]
在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI
4 Y7 X- f. u: i3 \) h2 b4 [5 ~9 e$ z1 J
% l3 g3 A/ b) C8 z: }2、创建模板项目,启动CubeIDE
2 |( f' [! V+ m
! [2 `1 j7 b3 ~9 d' u7 s
可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。
( I) H* [* T& m; l8 ]" H完成编译,执行下载,显示成功完成。
2 |; ?6 W2 e5 Y
% K# H2 E0 F5 @
* I( D' E( N: F3 \- L( x8 \
3、运行模拟- K( l% _1 ?/ X% D. Z3 b
上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,
+ Z8 L' W1 W& P7 {5 |这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,8 V" _; U# E- a8 H: G) R. ^
. L2 J3 J) r$ |* E
! ]# z% c/ [) ~移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
' m: f) D% y- A [1 g( T& f/ H$ O3 N( O; d1 D# e1 w4 z& |
& T1 o! n" o0 F! d9 s# ]: M
这样快速监测成功。; h( _4 Q1 z- b1 V* \
4、人工智能实现的分析
3 r2 Z y2 ?" g! _4.1 硬件平台的能力
% N+ B0 o2 A g" I& P5 U! w8 b, `WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,( ^5 u6 w8 \) _5 J: S7 @
- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽& } r4 P& p. o. {3 A! |' o
0 ]: p/ b1 R) E$ z; v# x* P) z; a! P9 K5 ~! j
4.2 人脸识别的流程和库的支持( F! v" O! {6 C: L5 C& l2 X
CubeAI的人脸识别是用如下层次实现
; E5 \) T- n) A
2 j d8 L2 H0 j, [4 \; I在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下
% _* n& T& D+ B( x5 L) n
: i5 G. o" K( E: C数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
9 d& j+ d0 a `4.3 程序代码分析9 ]0 c' [) D% |% x4 C5 ^
首先定义图形数据的交换空间,是一个320x240的采样空间
$ M( t! B2 v; ^/ B. t" R- static Frame_TypeDef frame ={ .buffer = buffer,# W/ Q0 t$ T9 h* J5 h
- .length = 320 * 240 * 2,
: {* L( f0 i, U4 ]* F& n" x8 E - .width = 320,. ]* i/ C b9 c9 A! v
- .height = 240
# |3 u0 q- ~; D, p - };
复制代码 主程序代码非常精简( F- q4 i& E2 e7 ~0 N/ [& I0 V) L
) c% e! Q8 j0 q/ l; J* K `- int main(void)3 K* h' C+ h0 j* g# s1 E: k3 o
- {
* c4 O( t) z* _- c4 B0 u' j - MPU_Config();- E/ c) Z+ q. L8 h, x
- SCB_EnableICache();
9 d' `: Y8 v) k# s9 @ - SCB_EnableDCache();) T- B& H* }, P
- HAL_Init();
( ~* B, o; A5 Q7 D- z# ` - SystemClock_Config();
; O3 O B X. M) H$ p: p% A - 9 ^: K, m) U4 Q3 b
- /* Initialize all configured peripherals */ W8 t! ]+ n9 V; [
- MX_GPIO_Init();/ b1 X$ x9 F1 P: k- V8 c9 M. v: m
- MX_USART3_UART_Init();
" R# C6 Y5 Q! ]/ [0 t9 j# [ - MX_LTDC_Init();. D9 S) Q9 P8 h; f: d& L( p4 P+ F8 r
- MX_I2C4_Init();* r9 f4 {6 r7 G' [
- MX_DMA_Init();
# I8 p. F. U% R8 N9 k7 A - MX_DCMI_Init();
9 b) n" F4 Y" i8 `1 r - MX_TIM2_Init();) l2 j. M. N0 B, P
- MX_OCTOSPI1_Init();
5 @8 F3 B1 b# @9 {/ ^8 ^ - MX_CRC_Init();# b4 f: k2 k/ L- f- R
- LOG("here");3 s, \0 v c" c+ d7 `1 w
- Psram_Init();) a: a4 g- ^# W6 ]( ^ o
) R" h1 K# M% D- /*OV2640 Init*/
1 f' n' O/ i4 t3 a$ d - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK
: X4 m; N: O3 f - OV2640_Init(&OV2640);
% \! q! ^; G" S - OV2640_ReadID(&(OV2640.ID));
: ]# l2 u$ e) n" B4 P( w - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);) }% ~! I0 n; }2 Z& M
- OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.) B! i7 j U8 W0 s9 S# | p
- OV2640_Flip();3 Y4 m0 u' M# k4 ]: c i
- OV2640_Start(); //initial IPL and AI7 Y2 }3 Z7 ]# Z3 w& E7 c
- STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);0 M& o" H6 n8 U: }- o; {
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */
* w8 N, G z" |# A* ~ - __HAL_RCC_CRC_CLK_ENABLE();
- I; O, m7 A+ g( |5 o: h - aiInit();
1 L1 u4 l! h. r9 O9 b& ` - frame_rgb565.data = frame.buffer;3 y) u4 R N1 A- }; ]& X% T8 {
$ p o; f* @2 o9 G; M+ }- while (1)
4 S0 o5 V0 Y% _. Z7 ~ - {, {4 A7 f* X) x
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);- T, D$ s9 s `0 s0 ^' |0 w
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);4 ~! e; [6 n1 B$ X$ ?
- 9 E; Q/ m6 Y0 }0 ]6 M- O0 [7 R
- // rgb565 320*240*2 to grayscale 320*240
4 b: z, D6 n/ n0 B6 { q( B, P - if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {/ x3 a* x/ z$ h8 q% n; t7 [; w
- while(1);) {9 u# p2 s3 H7 ?* b* x8 s
- }8 z: y0 \+ r U1 z" [. n
- // grayscale 320*240 to grayscale 96x96x2
r4 l" ]; ^5 i O( j2 E' {# L - if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {
: b9 U9 j2 Z" c2 P2 Y! b - while(1);; E; P: `) U8 m$ |
- }
# ~& w, G3 d0 [' B V6 d$ [
) C$ K2 I$ G+ ^8 c4 C0 h- //AI
% V# X+ |$ I1 k2 ~ - aiRun(buffer_grayscale_resized, network_output);9 b! U! z. n1 R$ m. n
- postprocess(network_output);
( K" c# Y+ D' f$ s
3 T9 O, r8 V a5 i+ s. o$ W3 F( r- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);4 f" N' T! T: M+ N
- HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);1 l2 |, P2 Q( T$ I8 B( M
5 U6 c2 m& b# E: L& S- }
2 O( v* ~: Q4 L$ y8 z3 e - }
- K( X' o9 t1 j' J4 \& }
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮,8 V* R1 c( c: T- N i
实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果, i! p0 M4 ?$ w# u
4 W2 b' Y, s8 U& F- ?8 |: d+ |
- aiRun(buffer_grayscale_resized, network_output);
1 s) V( O9 h2 @1 y0 H% w) M) h/ E4 [ - postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的,# Z: q% R. i2 v$ g7 r
- void aiRun(ai_u8 *pIn, ai_u8 *pOut)9 U0 s. r* L& Q, Q7 \
- {5 _' m9 e; G: w2 r v
- ai_i32 batch;
" d) ~7 w# I( W Q0 ~; _4 ]1 _: O - ai_error err;
7 @) W8 a" h' j, k- \6 c: I - ' Y2 k. K% J1 X& }
- /* 1 - Create the AI buffer IO handlers with the default definition */; t: |& p) ~: s P! x* p6 }
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;
( t; O$ o4 \8 A+ S - ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;# C) Z+ ~- K9 j* L
! | o1 x) M3 w/ i( |- /* 2 - Update IO handlers with the data payload */
3 V* x1 f4 W& y. A1 v5 g - ai_input[0].n_batches = 1;
( Y" E$ v0 F( r- ^) K8 J- z2 p - ai_input[0].data = AI_HANDLE_PTR(pIn);6 y# S- n9 i4 r. R# @5 V
- ai_output[0].n_batches = 1;9 t2 ]9 a ~% o6 h
- ai_output[0].data = AI_HANDLE_PTR(pOut);9 r! C7 H) B1 z# I: b$ w- h
' q% O1 l6 I; ?7 }- Z% y- batch = ai_network_run(network, ai_input, ai_output);& t/ f$ z D8 D# f: T/ ^$ {) ^
- if (batch != 1) {
- B! u# [4 }. u, j; E - err = ai_network_get_error(network);0 h) w% L9 F6 U1 X2 E
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code); m3 q# n8 C1 n
- Error_Handler();; h* d" [( u$ S6 c! G A9 j8 ^6 ]
- }
q8 G, ^" e" [$ |) \, H( Y - }( Z# |, @. K# P; a3 F& P, M) u
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,
; ~% j. U" g: l& u: W* X- ai_i32 ai_network_run(
0 f2 b" H) l8 r7 a3 Z - ai_handle network, const ai_buffer* input, ai_buffer* output)( u# t" E# o9 ?" U( j
- {& f5 }1 m3 V7 w0 u
- return ai_platform_network_process(network, input, output);4 |5 e$ u. `" `# h2 g) B, v; W
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。
. O3 G# Q# b: q: c) q. ]- m* |0 D/ O; ~/ e4 j- [/ O
5 小结, S: d: Y! ?. m0 Z; O
基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。' {* `% b4 Q+ [' W5 k
在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。 F( A ], _9 T
n& R+ |" G3 S2 E/ J1 N# O! R) R g3 { V% r
) x9 M+ Y: c6 G% Y* Q
+ ^: Q, u3 R1 ?3 U4 T* H# [% d
. Q! {2 q/ Z2 | U0 k0 D$ G/ M5 ?4 A7 I( `
4 Q. K' d, C% K& L4 u) C) U/ J1 W
" H; o* w7 f& b8 x; ]. }, D* v3 I! ^5 z9 t& h1 G. e
|
! ~* ^6 a( Z! m
, \3 d: w# W& w# B8 q
大佬求源码
UP求驱动程序