Tensorflow Lite Micro是tensorflow框架针对微控制器应用场景所专门设计的深度学习推理框架,它占用的资源少,运行时内存最低只需要16KB,同时其兼容tensorflow框架,依托于Tensorflow平台强大的生态背景,使得更多开发者可以方便的集成、使用AI算法,为端侧带来人工智能的新活力。其中Tensorflow Lite模型也被ST的AI工具所支持,但是我们这次是不通过STM32提供的AI工具,而是移植Tensorflow Lite代码去运行其模型。
: ~! f% X5 A# X( T( U; y$ B. ]) g
$ z6 X6 l3 x" S" J) U首先获取Tensorflow LiteMCU版的源代码:https://github.com/tensorflow/tflite-micro
7 e# ?: F) E' r3 O
/ `* w( a3 D- \# V0 B/ Z$ x根据教程获取工程代码:TFLITE-micro/new_platform_support.md at Main ·张量流/TFLITE-micro ·吉特哈布 (github.com)/ p' Y* m' ]2 s- f; n3 w- v+ o
0 g7 S. [% {( _
文件都扔工程里面,太多了,截图只是一部分。把CMSIS-NN库(算子加速)也扔进去,加速运算
: M8 U- Y/ f! H. c2 U$ T4 l3 _
7 K) e8 d ~! a8 ~. P: c( Q6 o
0 Y* V/ U |, p% p, V, p: I9 r5 @添加相关路径
& M; {- `& S% i. | x! h2 N
" Q$ z! M. k3 T H/ j! d& ?& E: s( Y: R- a. F9 P6 \8 e2 \
设置工程,使用AC6编译,关闭Keil的Microlib库
# x$ `/ h7 h0 e8 F
! {" p6 o4 W6 W: f' f- e' |8 n0 V9 V" P
编译选项使用-Os,这样代码体积小点2 ~& O) ?. S: X2 Z9 i* }9 Y/ Q8 P9 X7 q
3 [2 x& p6 B: A. _' c; q" P$ O: e; Z) s' C! s
图像预处理函数。模型要求输入神经网络的图像为灰度图,为完成摄像头获取的RGB彩图到模型输入需要的灰度图转换,需从输入的RGB565像素格式中解析出R、G、B三通道的值,再根据心理学公式计算出单个像素点的灰度,具体代码如下:- uint8_t rgb565_to_gray(uint16_t bg_color)& M0 N1 J, q- t* q6 g
- {2 j" C! l9 z2 f# y
- uint8_t bg_r = 0;
6 }/ {) k G S" f0 C - uint8_t bg_g = 0;/ L% g1 w0 | F: G$ h
- uint8_t bg_b = 0;
6 p: D: P- h+ B( q( f6 h; ^ - bg_r = ((bg_color>>11)&0xff)<<3;) y$ s: ~( d" v; o! `. W* [, \
- bg_g = ((bg_color>>5)&0x3f)<<2;
8 R. g! n2 `/ R - bg_b = (bg_color&0x1f)<<2;# G# W! M' V( y4 F7 x0 y
- uint8_t gray = (bg_r*299 + bg_g*587 + bg_b*114 + 500) / 1000;
2 S/ ]9 z, q! h8 z - return gray;
, Z5 ]6 G; s! x- r% D - }
E1 i5 d. M$ J6 l - & S/ x# W2 `) H A5 s$ {
- void input_convert(uint16_t* camera_buffer , uint8_t* model_buffer)7 O+ ^: V& p% K+ `4 \5 b% b6 _
- {
: [4 k+ r' F F, t$ P) q# g - int i,j;
% z2 ~0 s, v P B- F( p- O - for(i=0; i<96; i++)1 q+ J% p2 P: x9 k% ~4 m
- {. ^' S) `$ _3 o' y
- for(j=0; j<96; j++)
" d/ N6 t5 I; n ]" d1 w - {" \5 t" O0 z, \0 E! l
- model_buffer[i*96+j] = rgb565_to_gray(camera_buffer[i*2*320 + j*2 + 64 + 320*24]);
/ ^* M3 p, A: V" x$ @ - }) q4 V; P& c' J5 G( \
- }' @# S* Y9 m( k. q3 ^5 {9 F4 |
- }
复制代码 " H. {8 z, U l1 D; t4 I
在图像接收中断里面处理识别过程- void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)' b: m* N* [9 U$ c3 F: k
- {
" }" d+ m3 K$ x( ^/ C0 l; e - uint8_t person_flag;
- l9 G) ]+ r' n- N7 L
, L" U; k" x3 Z( Q' Q7 i0 _- //转换图像为模型可处理的大小5 ^" }6 y( h( c% n" v5 ^# k q& m
- input_convert((uint16_t*)_OV2640->frame->buffer, model_buffer);
+ r& j+ N; M# @0 P; G - person_flag = person_detect(model_buffer); //运行模型
# `/ {+ i q- W. F2 w8 K1 j9 u$ e -
% u% L6 h2 e/ E - LCD_Draw_Image(0, 0, 320, 240, (uint16_t *)_OV2640->frame->buffer);
5 C- b7 }8 x( P! v! ?- `! E: c - for(int i=0;i<192;i++)
$ X3 r7 C- Q& ^9 N; x% u7 o - {) u6 e. u1 j) a' S1 J
- LCD_Draw_Point(i+64, 192+24,0xf100);
2 Q" {3 z( ~, @/ e" e - LCD_Draw_Point(192+64,i+24, 0xf100);
: }; [: a' d6 c; _7 X+ s - LCD_Draw_Point(i+64, 0+24, 0xf100);
7 L7 W, t2 t" x1 e8 F, b i6 ^- [ - LCD_Draw_Point(64, i+24, 0xf100);
$ B/ c+ e: R7 a) L2 { - }6 t7 b9 S- @1 C p9 d
- if(person_flag!=0)LCD_Draw_String(0, 0, 320, 240, 32, "people");
( M' f) |' x9 D( V! u - # e3 b/ k8 {* K' s# N: u: @
- OV2640_DMA_Config(_OV2640->frame->buffer, (_OV2640->frame->length)/4);9 f7 p; e, \- G# }
- }
复制代码 # r8 Y, l/ F+ z6 ~
" I" ]/ h: B( U9 L% m% l
; o6 N: ]+ B" |1 L; l3 V' I
运行效果:
* [/ X- t5 V! n3 |' Q' a: y; p% b识别充电器(无反应)
& Z! W' o7 m+ E2 n7 _6 M6 Z( L2 O
& Y& v2 p* }5 M# q3 l$ `
5 n+ E) y$ J. O5 _& ?9 m
* P( Y, x; |+ q7 U识别打火机(无反应)0 r+ ~% J* j8 s9 g: N5 w* O+ {
& R1 i C7 C- l; m) W# R3 M9 u7 C! j, n- B6 E& K3 P0 t
识别人体(显示people)
; B5 N4 I& B+ ?5 V! W$ z
; t* \& M2 e* A4 r/ w$ j; a3 N3 J+ Y. _8 G- {) n) r
+ t+ P4 o) j# S' V8 D
- ?0 q& Q' F0 V' j" h8 m |