Tensorflow Lite Micro是tensorflow框架针对微控制器应用场景所专门设计的深度学习推理框架,它占用的资源少,运行时内存最低只需要16KB,同时其兼容tensorflow框架,依托于Tensorflow平台强大的生态背景,使得更多开发者可以方便的集成、使用AI算法,为端侧带来人工智能的新活力。其中Tensorflow Lite模型也被ST的AI工具所支持,但是我们这次是不通过STM32提供的AI工具,而是移植Tensorflow Lite代码去运行其模型。
5 M; [. s& G' T+ C3 ~
* ? i7 Q/ P/ @2 O# f/ {首先获取Tensorflow LiteMCU版的源代码:https://github.com/tensorflow/tflite-micro# {% T4 D; C) h
1 O: [, J4 d8 d* T, U9 M根据教程获取工程代码:TFLITE-micro/new_platform_support.md at Main ·张量流/TFLITE-micro ·吉特哈布 (github.com)
7 j( n% t- N. S) Z3 a' E0 T! w$ d' G9 q+ M1 Q
文件都扔工程里面,太多了,截图只是一部分。把CMSIS-NN库(算子加速)也扔进去,加速运算2 ~6 l5 A% {/ G7 v
" t& a; u; `5 p( n! J
: i" j: Q$ E: T3 C) n+ F6 z |, ~添加相关路径
: ]9 ~% a2 }' B$ X% w0 N$ H
& e: |3 v( x; p) d/ E. B( W7 b! r+ T0 s5 B2 ~
设置工程,使用AC6编译,关闭Keil的Microlib库' p v) Z3 {" o0 @
. ]/ H& r. Z) x% I
. l) |! Z* C) y5 g编译选项使用-Os,这样代码体积小点1 n# `: P- c# s6 g$ o% \# h
0 H* a- |2 C4 h' E; o' a
( y: }/ ^+ D% @1 ~# j图像预处理函数。模型要求输入神经网络的图像为灰度图,为完成摄像头获取的RGB彩图到模型输入需要的灰度图转换,需从输入的RGB565像素格式中解析出R、G、B三通道的值,再根据心理学公式计算出单个像素点的灰度,具体代码如下:- uint8_t rgb565_to_gray(uint16_t bg_color)
& w. X- l& m% i- p - {3 G" w9 E1 n" ~" J9 L- ^# z
- uint8_t bg_r = 0;
0 a: @( _! {- y( R( B1 n - uint8_t bg_g = 0;
% A7 n g4 G9 W5 W8 Y+ c) b5 N. c - uint8_t bg_b = 0;
1 O: z$ ?0 m4 R+ a - bg_r = ((bg_color>>11)&0xff)<<3;1 W! R, W2 l7 t* S5 u& Z
- bg_g = ((bg_color>>5)&0x3f)<<2;* y" G5 n; x- x# H& o
- bg_b = (bg_color&0x1f)<<2;
( R( E/ K7 I' o6 t9 N - uint8_t gray = (bg_r*299 + bg_g*587 + bg_b*114 + 500) / 1000;
3 d5 Q( G; {; {8 | - return gray;/ O" M( S. N% f5 d8 q' `
- }; R1 `. q# o4 r0 S; A2 J# ~ }" i1 n
6 P- b( ]: J2 u- void input_convert(uint16_t* camera_buffer , uint8_t* model_buffer)
$ `: c2 Z: ^+ n, N$ I9 x - {/ w. m$ Z+ a0 n. v$ s8 o+ Z0 `5 N
- int i,j;
4 x0 a3 Y! J E0 S0 l( N$ L - for(i=0; i<96; i++)& c3 u& y: B( E! s1 ~$ }& ~- U
- {
+ A3 X% `! D! K. V$ L- j D - for(j=0; j<96; j++)
7 g# K% u2 c/ s D" Z, c - {
# R6 n0 L' N. p& V8 [$ p - model_buffer[i*96+j] = rgb565_to_gray(camera_buffer[i*2*320 + j*2 + 64 + 320*24]);
- u% `7 S& C$ t+ G7 f - }
. T& j0 U2 k6 Q - }/ W3 x9 X9 T2 [. [" l8 L" \
- }
复制代码
9 @0 U$ k; X6 J2 T; X5 ]& @% f; B在图像接收中断里面处理识别过程- void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)$ u2 t$ [0 p9 G2 k$ Z1 v z
- {3 d7 g' n/ k& {6 j1 n4 B2 v
- uint8_t person_flag;
( l3 @: @$ j2 O/ I. { _ - ' E6 b% A- w. L8 A8 Y$ J9 S
- //转换图像为模型可处理的大小# y* a+ A/ S5 j: [# t: ]% l
- input_convert((uint16_t*)_OV2640->frame->buffer, model_buffer);; ]1 {8 u- l; D4 E- ?: E. c% m
- person_flag = person_detect(model_buffer); //运行模型* y: j6 ]0 r2 T/ l) C/ K9 {
- 8 }* A( R. T! a2 Y. a7 D
- LCD_Draw_Image(0, 0, 320, 240, (uint16_t *)_OV2640->frame->buffer);
|1 U2 }9 d* e; d7 d2 M - for(int i=0;i<192;i++)- E- v3 h% G5 l( K' c/ r: _& d4 ^
- {
2 |- v# U6 _, M. x$ {8 \/ J6 S - LCD_Draw_Point(i+64, 192+24,0xf100);
/ @8 ^5 p4 l, `. Q - LCD_Draw_Point(192+64,i+24, 0xf100);
6 V8 e( \; v! i2 t - LCD_Draw_Point(i+64, 0+24, 0xf100);0 ?2 L B$ W4 V: q% W n
- LCD_Draw_Point(64, i+24, 0xf100);2 H- Y% q+ w$ Y0 x# P; Z2 |
- }
8 N4 ?: c+ f; a8 r% M - if(person_flag!=0)LCD_Draw_String(0, 0, 320, 240, 32, "people");# e: ~7 r0 R) ?! @) \0 a
- & Y0 P" u6 M6 k6 ^, e
- OV2640_DMA_Config(_OV2640->frame->buffer, (_OV2640->frame->length)/4);# S1 ~2 i4 n* Z/ M& ]% x
- }
复制代码 * o) k. G; J- z! _8 E1 @, X
- V) {/ m2 ]. y" W; h, x
& y ]: g- E/ c运行效果:
, I1 w8 a0 _1 v% ^: o识别充电器(无反应)
8 Q' i8 G4 L6 ~: w: U
! J+ E O. p* |: {
" D. V$ G' z6 v$ k& p3 f
0 N8 y* |4 I1 ?5 I2 p& G识别打火机(无反应) K9 R3 J! |3 x7 Z3 \1 Y
+ U; `* Z2 f' K) H# @! N' [9 u' z
识别人体(显示people)
) P$ D) p; c8 `. o N* O
& F& _2 D& B1 M, j3 \
9 R) I$ X) d' W% {: {' Y- H! p( o0 K, K5 H$ M4 p( n1 P* ?
& I6 T0 O) U$ }& h1 z
|