Tensorflow Lite Micro是tensorflow框架针对微控制器应用场景所专门设计的深度学习推理框架,它占用的资源少,运行时内存最低只需要16KB,同时其兼容tensorflow框架,依托于Tensorflow平台强大的生态背景,使得更多开发者可以方便的集成、使用AI算法,为端侧带来人工智能的新活力。其中Tensorflow Lite模型也被ST的AI工具所支持,但是我们这次是不通过STM32提供的AI工具,而是移植Tensorflow Lite代码去运行其模型。8 E7 t: S, ?5 ?4 E" ]) f& @7 |
$ q3 [ _7 ?) o$ s) p: u9 ^首先获取Tensorflow LiteMCU版的源代码:https://github.com/tensorflow/tflite-micro
' G' Z e! p" g6 y# ?& {6 g" O+ m0 x
# q1 y0 I& T3 r, k) H根据教程获取工程代码:TFLITE-micro/new_platform_support.md at Main ·张量流/TFLITE-micro ·吉特哈布 (github.com)' @. s+ Q, d* p7 Z: ^8 J& A0 K
+ U9 z6 m/ u" n- t' q文件都扔工程里面,太多了,截图只是一部分。把CMSIS-NN库(算子加速)也扔进去,加速运算
1 S/ k, g1 f& O; I2 n. ]% l( e
' X/ D( p! D4 P( l6 i1 \) Q# A9 o# N$ A" f, i
添加相关路径
. D6 O0 c$ ^0 b
( D2 V0 `' {& L& D8 y1 X S% T
; t) l% C0 \* q4 q* t设置工程,使用AC6编译,关闭Keil的Microlib库
, E9 S7 P1 v" c! T1 n& E" b4 K9 |! ?6 F
* ^, s8 o0 N+ Y& ^" R: `& U
6 @5 m( D" S* [2 ?/ `/ m编译选项使用-Os,这样代码体积小点
& J& @+ W+ A# u8 G3 V4 l% a5 ^
8 `3 ~9 i5 Y" |# k+ y% M
4 V5 G# y5 `% c! @
图像预处理函数。模型要求输入神经网络的图像为灰度图,为完成摄像头获取的RGB彩图到模型输入需要的灰度图转换,需从输入的RGB565像素格式中解析出R、G、B三通道的值,再根据心理学公式计算出单个像素点的灰度,具体代码如下:- uint8_t rgb565_to_gray(uint16_t bg_color)
7 o+ D0 \4 j( C9 ^. D/ \" E3 P/ t - {
1 i# w( T! n9 e# a; p D - uint8_t bg_r = 0;6 ~" c9 w9 Q- j& p
- uint8_t bg_g = 0;* ]) M. y" a& H4 |6 B6 z: G
- uint8_t bg_b = 0;7 s& Y& w7 L' ?" U9 R3 G
- bg_r = ((bg_color>>11)&0xff)<<3;9 P; l. S, }3 p3 |* L2 A/ t
- bg_g = ((bg_color>>5)&0x3f)<<2;* i8 h6 P) e/ [2 ~1 n s
- bg_b = (bg_color&0x1f)<<2;
1 d0 [8 a& t# R9 v, V" [ - uint8_t gray = (bg_r*299 + bg_g*587 + bg_b*114 + 500) / 1000;
1 o' a! \+ z4 d8 C/ O - return gray;4 P# g/ I& y7 n- r2 J' x/ Z
- }+ _/ ~+ X/ f. A5 v; G v/ S
T3 m9 ^1 A4 b) V$ `1 q9 }, ?- void input_convert(uint16_t* camera_buffer , uint8_t* model_buffer)3 F* q i/ y# g+ K( \( }9 }
- {
: [9 b: ]& I1 T1 @; R. c - int i,j;
: V! z4 E; S6 @2 p Q - for(i=0; i<96; i++)% q% p3 H/ R x* s3 B
- {4 l) p+ R L/ ?$ a
- for(j=0; j<96; j++): C9 p7 F- }0 a- `7 s* K
- {6 Z" r0 u { O# Q! A
- model_buffer[i*96+j] = rgb565_to_gray(camera_buffer[i*2*320 + j*2 + 64 + 320*24]);
6 k' `% [6 O6 W3 o - }
4 W7 K7 [$ q$ U4 l$ C - }
- ~! M8 Q: N4 W% q" t - }
复制代码 1 ]# x. [: u+ N2 q1 m& s2 i, b
在图像接收中断里面处理识别过程- void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)) C- {( H% y# I/ K' o) t/ A
- {
" o2 C P6 R1 o# ?5 q& ] - uint8_t person_flag;
( W5 M) C5 N* S
! J k) K( b% Y- v- W- //转换图像为模型可处理的大小
) _7 ^! [' r% {: w* G8 ]5 \ - input_convert((uint16_t*)_OV2640->frame->buffer, model_buffer);8 V q) J+ z9 b2 K/ {. T
- person_flag = person_detect(model_buffer); //运行模型
6 t3 a4 c1 U- j* r+ D" O - & o# i" `7 v5 ~# q& h
- LCD_Draw_Image(0, 0, 320, 240, (uint16_t *)_OV2640->frame->buffer);
, T- S- f3 D# @. \/ M - for(int i=0;i<192;i++)
: N- B# ^/ s/ l6 k# o - {
5 ]9 G- X4 J1 m- P. B. k - LCD_Draw_Point(i+64, 192+24,0xf100);
+ {0 T3 |: N9 ?3 f b) X - LCD_Draw_Point(192+64,i+24, 0xf100);9 E3 E& {2 K% H2 ~- \
- LCD_Draw_Point(i+64, 0+24, 0xf100);* t2 t7 R9 s/ o! C3 b& S# ]
- LCD_Draw_Point(64, i+24, 0xf100);, B& M, Q( @2 S5 A
- }' X7 l/ {5 i: J
- if(person_flag!=0)LCD_Draw_String(0, 0, 320, 240, 32, "people");
- `% |; z; P( ?& b3 n/ K5 Q* o! J - 6 V; s$ [& f$ S1 n' `6 a8 g
- OV2640_DMA_Config(_OV2640->frame->buffer, (_OV2640->frame->length)/4);
5 \+ F: F, j- ?( g T8 y1 C - }
复制代码
; M+ Y/ w' V" r; J' @+ f# L& b6 I0 H9 G Q/ \
/ v6 e% d ^$ R, C9 u
运行效果:' B0 Q1 P' m# ?4 f" @+ L) z9 s7 |% U
识别充电器(无反应)- A' y- S/ n$ a$ ~
* O7 g. \" l' R# a
% ^1 p8 Z5 C8 b1 T7 V
9 E1 j: c/ I( B1 o5 Y; j; g识别打火机(无反应)
, o0 p1 w" S; X6 l4 S% S
# R6 U& U5 R( R" E% J
0 H/ x' A$ N' H$ p2 v6 m7 _识别人体(显示people)7 w0 O8 r( E: y( f
. W2 Z7 `1 ?5 m
+ I+ ^3 `- E4 h* H, `; p+ e2 D0 j; @8 [! p& s! s# w6 Q
" G1 J" M% u. i8 o2 l( a. C |