Wio Lite AI视觉开发套件——人脸识别快速实现
9 h' |+ Q8 _8 ~' Q- {5 ?, V4 v$ j/ j1、在完成基本硬件评测和软件开发环境配置之后,可以快速实现人脸识别的任务8 |; s4 {$ C' G9 `2 g
2、首先按照新的ST-link连接,把Nucleo的st-link调试如下图连接,
, K! o" k& v, w
6 }' ]/ J% x7 l Q采用如下接口对应联络到WIO Lite AI开发板,
) o7 a8 S; m9 G; M B: D8 L) r/ }2 O1 C1 a% Z! h6 u6 z, {, b
3 O9 c9 q* h5 q5 k* u
使用调试夹子快速连接,就可以,如下图,9 d1 `0 p2 n- u7 B2 i# m# L, u
3 V0 I& k2 X+ y! H4 Q在项目的接口可以发现ST-LInk在Port Com8,另一个是COM5,连接WIO Lite AI6 U" l! @ q0 ?
# N0 |# b9 E9 z9 y/ Y
$ P+ S' {* z7 |7 [
2、创建模板项目,启动CubeIDE0 ~8 Q' n% K/ ]- I6 c! P3 ^
' T! r7 b" l4 M2 a& ]* @0 C7 w可以找到人脸识别的模型,Person_detect.tflite,这个是用于人脸识别的tensorflow 模型。这个是压缩后的整数型数据,人脸识别在标准情况下,现在已经可以做到90%以上,那么压缩之后,精度下降,识别精度明显下降,但是仍然可以完美实现该功能。
$ P+ o+ E4 a* t0 S: Y, \完成编译,执行下载,显示成功完成。" x6 o: B- q6 k d
( \8 _& S2 E( W2 S1 O1 \
$ W& y& _4 f* p. N& Y& T& r3、运行模拟3 Q+ `9 u! ?! Y5 _. T1 y d( a
上电后,摄像头捕捉图像,并显示在LCD屏上,当图片是空白,或者没有发现人的时候,显示No-person,
~: ~! A# V; F& |( z3 z/ x这里用手机摄像头遮挡面部,就显示没发现人脸,显示准确度可以达到80%,6 j6 U( a0 e% h
# b# H2 G+ N! P$ S# a* ]# H
) _9 }: k$ b1 K$ n- F$ R2 p
移开手机,露出人脸,就迅速监测到人脸,显示Person,同时计算出准确率61%。
0 b1 T% q7 I; w0 A5 @
4 X! _" i8 S8 W" C& C0 V( O
9 {. P/ m5 l* L3 V这样快速监测成功。
0 @3 ]& O: p, ? R8 N/ h4、人工智能实现的分析9 q3 X1 q( ?8 Z% M
4.1 硬件平台的能力; u3 d6 t. T; l+ y# v& [" O9 ~
WIO LiteAI采用的是STM32H725,工作频率高达550 MHz的Arm® Cortex®-M7内核(具有双精度浮点单元),可选扩展室温范围最高为125 °C (*),只有一个内核,仍然展现强大的计算能力,可以无延迟实现图像处理和人脸识别。在图形上采用的高性能的支持,具有以下两个图形实现和加速功能,- R I$ P' @) Z$ _: y
- LCD-TFT控制器接口支持双层图形
- Chrom-ART Accelerator™提高了图形内容创建速度,并为其它应用节省了MCU内核处理带宽$ c6 A$ Z3 g2 @: z
* V0 }. N; t% O8 {2 k* D
. W* u0 l9 f6 g3 y* d1 H1 t9 |$ d
4.2 人脸识别的流程和库的支持 I8 C- e; u0 t
CubeAI的人脸识别是用如下层次实现% H, X$ m/ D9 P* g) M) ?
6 r( ]5 [. V2 ^* V2 k0 g8 E' {
在底层硬件上,实现板级支持,更上一层是STM32的人脸识别模型,实现具体的应用,实现过程的数据流程如下5 D/ o# t6 O" j$ X( J1 R
* G* A! S# h7 K7 d" c
数据依次在上述流程中逐级计算,根据人工智能模型实现人脸的识别精度计算,当大于计算值以后就迅速提出结果并显示出来
5 x" @6 F7 B7 r: }# o2 E2 }5 O4.3 程序代码分析
; Y& s8 E- A# y3 X2 t- w8 i7 v首先定义图形数据的交换空间,是一个320x240的采样空间
3 Z; v4 X" _' U) e3 V( b0 T9 Z- static Frame_TypeDef frame ={ .buffer = buffer,3 y& F F, {2 j' x9 H) |
- .length = 320 * 240 * 2,: }! Z A) i8 q i6 J5 [& u
- .width = 320,
8 T! G' v1 F7 ?" U. Q - .height = 240! K- Q4 m- W5 ?' W9 {7 h1 S5 y3 a
- };
复制代码 主程序代码非常精简
- l A5 M) _: p/ k2 }' Z# g/ `- - I7 d. q# b7 L" N; a5 N5 T
- int main(void)
3 A2 G3 @: |6 t) w$ | - {
; Y; C+ o& z# ]4 ^4 p3 | - MPU_Config();
6 R2 t, D8 j3 W$ Q5 w# p8 k - SCB_EnableICache();+ X) x3 [( w- L! a9 B" N$ m4 K2 f
- SCB_EnableDCache();* ~, z O P6 q8 H9 G1 ]
- HAL_Init();
( }. g( C4 _; T) C( p - SystemClock_Config();+ P# U* j4 B8 @' n) y. V+ c0 A
0 {. v' N w% p T8 a( U. B- /* Initialize all configured peripherals */* A; |3 d) a3 [/ E
- MX_GPIO_Init();% [+ h" a( \1 X }
- MX_USART3_UART_Init();$ |/ x. F2 r/ L- T2 S: a5 H
- MX_LTDC_Init();% a7 ]/ o$ q8 G- J
- MX_I2C4_Init();8 K# |. r4 e d0 b
- MX_DMA_Init();; A! g2 p Y, d# Y# L0 u
- MX_DCMI_Init();7 x' k" B' e0 |" p- u" ~( U& V
- MX_TIM2_Init();( }$ \' l# d: k8 j2 q
- MX_OCTOSPI1_Init();
5 I4 N: f1 t" q1 w$ B - MX_CRC_Init();2 n4 z- b/ V# a
- LOG("here");
- S; v0 S: y. i) ]3 f - Psram_Init();
$ z6 o1 f v/ e+ y$ x/ y0 c* X; J# J - ! A2 M- a2 u+ o7 }
- /*OV2640 Init*/# Q/ W+ Y9 M! L, n5 O
- HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //XCLK
5 B- h5 h' p3 y& y - OV2640_Init(&OV2640);, [( y% g$ X5 B1 N3 O
- OV2640_ReadID(&(OV2640.ID));
& l* V- W! i& B7 l) x - LOG("ID: %02X %02X \r\n", OV2640.ID.PIDH, OV2640.ID.PIDL);1 w0 R% U a0 h+ q* S
- OV2640_UXGAConfig(); //flip after all the camera setting ,or camera setting will change REG04 value.* `2 p% f$ t8 R' v! X& f) t
- OV2640_Flip();
' K8 u6 F$ j7 ?# u( _1 n - OV2640_Start(); //initial IPL and AI
" j% U% g& {. f - STM32Ipl_InitLib(buffer_ipl, IPL_BUFFER_SIZE);) l8 t f/ ~* ?) {7 Y" T
- /* The STM32 CRC IP clock should be enabled to use the network runtime library */
+ O, W0 |1 v0 s6 N( r. k - __HAL_RCC_CRC_CLK_ENABLE();5 W3 M8 P( K' n: w
- aiInit();0 ?2 M, Z' m' k6 r" e
- frame_rgb565.data = frame.buffer;8 A5 {1 R4 q! `
- B \- j3 h$ u' ]4 t
- while (1)" Y4 @$ ^* Y: e& @2 ]
- {
# {4 [6 Q4 c5 ~( x - HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
6 _0 z' |* r+ t - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);' u: G4 Z2 |9 K8 y, H
- m3 g6 P! w( ^2 q) m' n5 c
- // rgb565 320*240*2 to grayscale 320*2402 H% t2 h$ Y' ?" Q
- if (STM32Ipl_Convert(&frame_rgb565, &frame_rgb565_grayscale) != stm32ipl_err_Ok) {6 g" W% ?7 U" V0 q1 I' x8 d' q
- while(1);
% R p2 l$ e0 t2 l) a$ g3 i - }
$ i* P# L: ]. `# h& o6 k" q - // grayscale 320*240 to grayscale 96x96x2
+ C1 `! a/ b: x; |5 C0 g, z - if (STM32Ipl_Resize(&frame_rgb565_grayscale, &frame_grayscale_resized, &roi) != stm32ipl_err_Ok) {' h' |3 D% f' {! ^- i
- while(1);) B+ \6 F/ e7 c6 F4 S3 y
- }
- I' A' t6 s9 ^ v
! V, S' O R1 r, e/ A1 c- y0 T' Z- //AI
, N: Z: F7 r6 o9 [* z$ S: J ] - aiRun(buffer_grayscale_resized, network_output);2 b; I' _6 Y- Q/ O/ H
- postprocess(network_output);
& q! s5 [: W* C2 v - / |& a; x. m. k" v
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
7 S1 F" Q$ w1 @9 y: a0 e9 U - HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET);
9 |; V* }# G; x! d) t: R0 ~
0 Z7 r1 z! k! O' W! E s2 G' a: i- }
7 N, G+ I# f: b X7 B q9 @ - }
5 g/ e, {* }1 X3 F6 b
复制代码 在启动硬件初始化之后,就进入识别循环,当识别出人脸就直接把对应的LED点亮," q6 `7 |" e- k- o2 l$ p7 ^
实现人脸识别的函数是aiRun,对图形交换空间的数据分析,并直接输出神经网络计算的结果 l t. d7 F& O$ ~
* Z3 r7 R0 Q+ l$ B
- aiRun(buffer_grayscale_resized, network_output);7 i6 e6 q, b3 m. |
- postprocess(network_output);
复制代码 这个函数是在"ai_inference.h"文件中实现的, e5 |' x. c! p: d5 h. N
- void aiRun(ai_u8 *pIn, ai_u8 *pOut)
; E$ c+ v# a, |4 s- `( }% F - {
' h4 e$ I2 z( T3 H3 ]9 e5 p - ai_i32 batch;
( Q7 X/ k, k F: X - ai_error err;! U4 M& U0 I) e8 s1 m
- 9 Q6 O9 R7 Y6 R
- /* 1 - Create the AI buffer IO handlers with the default definition */' n$ Q8 ?, y* O) f
- ai_buffer ai_input[AI_NETWORK_IN_NUM] = AI_NETWORK_IN;0 `/ T9 G2 E) W- z
- ai_buffer ai_output[AI_NETWORK_OUT_NUM] = AI_NETWORK_OUT;
& g0 F% M! t& K" P6 @ r
: h% U- ?( L, w1 k; ]9 e- /* 2 - Update IO handlers with the data payload */7 @+ ~+ @. C" y9 C
- ai_input[0].n_batches = 1;
$ y1 z7 H) z S( Q4 p! K$ l - ai_input[0].data = AI_HANDLE_PTR(pIn);# h5 W: g' R% l$ }! ~
- ai_output[0].n_batches = 1;3 j- r% r5 M# K! [9 J
- ai_output[0].data = AI_HANDLE_PTR(pOut);1 e9 J) q6 `' B4 h Q: ?2 T
0 `. G# ~- a4 D( F5 ^- batch = ai_network_run(network, ai_input, ai_output);
: Z) L2 o. T7 M4 v# D0 H1 u+ U - if (batch != 1) {" @: m$ R( m, }( w& u" A, E1 D
- err = ai_network_get_error(network);! Q6 {& }% d' @( f2 M' I/ k
- printf("AI ai_network_run error - type=%d code=%d\r\n", err.type, err.code);0 x' i/ r3 b: B) x& X* ~3 C
- Error_Handler();' y+ S% H2 N) d
- }% F2 `; _7 B! K3 E$ D6 r4 v
- }
& F; }, E2 { Q; {* R$ A7 W2 ^* H+ }% f
复制代码 上述过程就是流程图数据流实现的过程,读取经过预处理的图像数据,然后再ai网络中计算,输出计算结果,
* `2 U8 }: b) q; T% k- ai_i32 ai_network_run(
" v& y( q* I! j# ?% u+ u - ai_handle network, const ai_buffer* input, ai_buffer* output)7 m+ S4 O4 d* r
- {$ s3 U- B/ m# z
- return ai_platform_network_process(network, input, output);1 j6 \! W) t: s
- }
复制代码 上述处理,需要计算网络,这个是再ai_model中定义的,然后读取输入数据,形成输出数据。; f4 W9 c; f2 u" B' {- R
% Z$ T% o8 G+ [3 m! u5 小结
8 ?( C3 ?5 o2 B7 c7 L% N3 B 基于STM的cubeAI,通常已经提供了一个快速部署的流程框架。对于开发者,只需要自定义人工智能模型,然后导入到新建的工程中,按照提供的API逐步实现数据流程,就能够在项目中嵌入人工智能的功能。
) r6 p D# I0 V6 S0 L$ h. T 在上一个文件中提高的,对应模型的生产,采用CubeAI中的命令行指令,stm32ai就可以完整实现。这个CubeAI极其配套工具,就是一个完整实现人工智能嵌入的工具,虽然安装和使用流程比较多,但是能够实现这样的效果还是非常理想的,在硬件性能和软件功能,达到完美的结合。
5 F' p0 ^" b, d! T' X. X1 T1 X; j. E7 V1 e, i
" k1 u! r% _ O! O6 R/ N( w/ _9 w8 s: z
- q' Y4 U: L6 Q* {2 F9 N- @1 K! z% B0 [1 _$ D( N" z
0 b& }/ a2 ?/ ?. \" u/ |' S0 T1 J
1 E) |! P! n5 C, P6 u/ {
/ h. p$ g3 \ g
x# t& V& w; w" F0 Z |
大佬求源码
UP求驱动程序