Tensorflow Lite Micro是tensorflow框架针对微控制器应用场景所专门设计的深度学习推理框架,它占用的资源少,运行时内存最低只需要16KB,同时其兼容tensorflow框架,依托于Tensorflow平台强大的生态背景,使得更多开发者可以方便的集成、使用AI算法,为端侧带来人工智能的新活力。其中Tensorflow Lite模型也被ST的AI工具所支持,但是我们这次是不通过STM32提供的AI工具,而是移植Tensorflow Lite代码去运行其模型。
; C2 f& p& @: O: o5 U" j& Z
w+ k% ?+ Z# k- E9 s, r; q首先获取Tensorflow LiteMCU版的源代码:https://github.com/tensorflow/tflite-micro, w; ^9 h3 O# |
& @+ i6 K' p# v4 }根据教程获取工程代码:TFLITE-micro/new_platform_support.md at Main ·张量流/TFLITE-micro ·吉特哈布 (github.com)! M7 Q ?/ ^4 c: E6 v0 D3 Q
! u/ y+ }1 t" g! n1 w/ i, q
文件都扔工程里面,太多了,截图只是一部分。把CMSIS-NN库(算子加速)也扔进去,加速运算9 N4 s8 @" ?/ o9 K! ~
2 R8 L* D4 t9 ^
# k! K% \& g4 f8 P4 O添加相关路径) \* D1 ~3 \+ w3 C4 J
9 v! f+ i1 }' w2 `
( ?) M1 Q/ V1 O4 G& C7 ]( G% V' K" Z设置工程,使用AC6编译,关闭Keil的Microlib库
- t4 F* f1 u! O/ Q. @
. h& ^ A: O5 G- p( j6 u: E7 ?) f2 N8 u1 X# ]5 z' m
编译选项使用-Os,这样代码体积小点% V) d+ V1 {5 E" z) j1 R
9 ~$ I1 j- W( R% E* ~( V" X7 S( X# e. e( {, W! z
图像预处理函数。模型要求输入神经网络的图像为灰度图,为完成摄像头获取的RGB彩图到模型输入需要的灰度图转换,需从输入的RGB565像素格式中解析出R、G、B三通道的值,再根据心理学公式计算出单个像素点的灰度,具体代码如下:- uint8_t rgb565_to_gray(uint16_t bg_color)1 c' G5 _) ~( c; V: R. `/ ?
- { Q! Y4 O. I3 E( O+ t2 u7 U: m$ V
- uint8_t bg_r = 0;, S. U5 L7 C, Y5 e* w+ g4 {
- uint8_t bg_g = 0;9 H( o- d7 ]- \5 e9 U( [' x* N" D3 A
- uint8_t bg_b = 0;
" D% t: a3 o0 T7 n" P - bg_r = ((bg_color>>11)&0xff)<<3;
0 E7 B0 U- U8 b" B7 R: @0 w1 ^ - bg_g = ((bg_color>>5)&0x3f)<<2;# v; A4 s& [& M9 M7 {1 \3 R
- bg_b = (bg_color&0x1f)<<2;
* K- S$ T# N% m1 f - uint8_t gray = (bg_r*299 + bg_g*587 + bg_b*114 + 500) / 1000;. [: i9 \/ Z( N
- return gray;8 W/ D. Q! m. T8 z
- }% R7 {( @8 f2 }: [+ j1 b3 |
! B2 j5 I+ ~7 S- void input_convert(uint16_t* camera_buffer , uint8_t* model_buffer)
& p8 x( T% D& n2 D/ ?2 y/ B - {
5 M4 O( [ V+ L - int i,j;
+ }9 b! e$ x9 [5 u - for(i=0; i<96; i++)% Z. b8 S x' G1 k
- {
' K, ~; p) @- j2 b - for(j=0; j<96; j++)
$ q" V$ W0 \/ o; O- H - {
, `' L* \% B8 \, z2 \9 }# [( H - model_buffer[i*96+j] = rgb565_to_gray(camera_buffer[i*2*320 + j*2 + 64 + 320*24]); B2 j4 y# w/ Z( b3 U) S5 s
- }
" z* l2 O! d; Y0 y6 T - }
7 F$ ]2 r: g9 b2 k - }
复制代码 4 j3 ?/ k9 o$ h8 n, S
在图像接收中断里面处理识别过程- void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
9 ^- u& b! o- V) K - {3 m1 T5 F4 H: p. D, U8 H- a" w. A& W5 z
- uint8_t person_flag;
; o3 M8 O1 V% B( y& I' |0 v
; @' ^8 N/ E% p) L; _- //转换图像为模型可处理的大小
l3 V" H8 g- l- V. C - input_convert((uint16_t*)_OV2640->frame->buffer, model_buffer);
! M x' Q8 g! ^) F - person_flag = person_detect(model_buffer); //运行模型) k/ m8 S, ~6 Q( r' j) c/ I
- ) ^- V; |" U5 n+ B, u: h
- LCD_Draw_Image(0, 0, 320, 240, (uint16_t *)_OV2640->frame->buffer);
4 Z# F9 w3 ?+ Z: D3 `( r - for(int i=0;i<192;i++)
5 a- L1 A1 S3 U; H, ?" ]; Z - {
5 |, l, ~ p4 P/ a4 U& J& A- m- a - LCD_Draw_Point(i+64, 192+24,0xf100);
7 m& B& n' O. X- c& _3 f; O u/ d - LCD_Draw_Point(192+64,i+24, 0xf100);
' f* @; h6 |# F, |6 \# Y1 I - LCD_Draw_Point(i+64, 0+24, 0xf100);
7 N& r4 K, N T - LCD_Draw_Point(64, i+24, 0xf100);
4 v3 [' G' ]0 G! d* X0 G - }0 L8 }$ h" o% @3 ?- Q
- if(person_flag!=0)LCD_Draw_String(0, 0, 320, 240, 32, "people");( J8 I( I0 \& I7 ?6 ~8 \
- 7 F& |1 N* Y: t2 n: x: U7 T2 m
- OV2640_DMA_Config(_OV2640->frame->buffer, (_OV2640->frame->length)/4);; P- h1 x! n/ n
- }
复制代码
) d* |) {7 o r$ ]9 Z
: ?! |9 J6 f. ]- p0 m. i% H
4 I% K; z/ i+ n6 J( L3 c运行效果:
$ N1 |6 L5 R a8 }6 j0 V0 C7 J1 H识别充电器(无反应)$ _0 P0 T; g# {5 R5 j5 a! w
& \) ?2 R# G! b( S& X4 j1 |8 A3 S. g
7 ]! w' g0 n* k4 k* L
7 p' j9 t9 W1 n7 U7 K+ Y
识别打火机(无反应)/ a. V- g* I$ G( f
: A) m6 y$ N# H0 ~. K/ Q1 O {
: Q" W: M1 e5 a9 O( n. Z识别人体(显示people)/ V; D( A6 J, N- X9 j+ F
* X7 b3 m% [ @1 u& y4 p* m
$ f- W% S9 D2 X& ]& r6 u' e
2 n1 S5 Y. R7 ^9 I: U3 i
$ c) N. @4 L7 ` |