【简介】
本文实现了一个通过摄像头采集图像,然后显示图像到屏幕上,运行TensorFlow Lite运算引擎,实现cafar10的神经网络模型。
【演示视频】
【TensorFlow简介】
TensorFlow 是一个端到端开源机器学习平台。它拥有一个全面而灵活的生态系统,其中包含各种工具、库和社区资源,可助力研究人员推动先进机器学习技术的发展,并使开发者能够轻松地构建和部署由机器学习提供支持的应用。
TensorFlow 是数据科学家、软件开发者和教育工作者主要使用的开源平台,用于使用数据流图形进行机器学习。图像中的节点代表数学运算,而图像边缘则代表节点间流动的多维数据阵列(张量)。这种灵活的架构允许将机器学习算法描述为相关运算的图形。可以在便携式设备、台式电脑和高端服务器等众多不同平台的 GPU、CPU 和 TPU 上训练和执行这些代码,而无需重写代码。这意味着各种背景的编程人员均可以使用相同的工具集进行协作,从而显著提高效率。该系统最初由 Google Brain 团队开发,用于研究机器学习和深度神经网络 (DNN),其通用性同样适用于其他各种领域。
【cafar10简介】
CIFAR-10 和 CIFAR-100 是 8000 万张微小图像数据集的标记子集。它们由 Alex Krizhevsky、Vinod Nair 和 Geoffrey Hinton 收集。
CIFAR-10 数据集由 10 个类的 60000 张 32x32 彩色图像组成,每类 6000 张图像。有 50000 张训练图像和 10000 张测试图像。
数据集分为5个训练批次和1个测试批次,每个批次有10000张图像。测试批次正好包含从每个类中随机选择的 1000 张图像。训练批次以随机顺序包含剩余的图像,但某些训练批次可能包含来自一个类的图像多于另一个类的图像。在它们之间,训练批次正好包含来自每个类的 5000 张图像。
以下是数据集中的类,以及每个类的 10 个随机图像:
这些类是完全互斥的。汽车和卡车之间没有重叠。“汽车”包括轿车、SUV 之类的东西。“卡车”仅包括大型卡车。两者都不包括皮卡车。
【显示功能实现】
GD为我们提供了很多例子,我们可以直接在提供的例子上进行修改就能得到期望的结果。
显示部分没啥好说的,主要注意一下显存地址就可以了。
初始化参考,这里我只使用了TLI的层0。
void app_lcd_init(void)
{
/* LCD configure and TLI enable */
lcd_config();
tli_layer_enable(LAYER0);
// tli_layer_enable(LAYER1);
tli_reload_config(TLI_REQUEST_RELOAD_EN);
tli_enable();
}
复制代码【摄像头功能实现】
同使用GD的例子就行
初始化参考
void app_ov2640_init(void)
{
ov2640_id_struct ov2640id;
nvic_irq_enable(DMA1_Channel7_IRQn, 0U, 1U);
/* camera initialization */
dci_ov2640_init();
dci_ov2640_id_read(&ov2640id);
/* DMA interrupt and channel enable */
dma_interrupt_enable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
dma_channel_enable(DMA1, DMA_CH7);
/* DCI enable */
dci_enable();
dci_capture_enable();
delay_1ms(100);
}
复制代码【TensorFlow移植】
因为TensorFlow代码非常多,编译一次需要很久,我们可以使用生成lib库的方式减少编译时间。
工程结构
注意要选择生成lib库
这样我们只需在最终工程里面加入lib库就可以了
适配log接口,这里我在工程里面实现了printf,所以使用printf打印就行。
#include "tensorflow/lite/micro/debug_log.h"
#ifndef TF_LITE_STRIP_ERROR_STRINGS
extern "C" {
#include "app_init.h"
}
#endif
extern "C" void DebugLog(const char* s) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
// Reusing TF_LITE_STRIP_ERROR_STRINGS to disable DebugLog completely to get
// maximum reduction in binary size. This is because we have DebugLog calls
// via TF_LITE_CHECK that are not stubbed out by TF_LITE_REPORT_ERROR.
printf("%s", s);
#endif
}
复制代码【cafar10识别实现】
首先是要确定模型的输入和输出,本次我们实现的是cafar10模型,使用模型的输入就是32x32的RGB888的图像。
摄像头采集到的图像是240x272的RGB565,所以要先进行一个转换。
void Rgb565StridedToRgb888(const uint8_t* pIn, uint8_t* p888) {
uint8_t* pSrc = (uint8_t*)pIn;
uint8_t* p888out = p888;
unsigned char R,G,B;
uint32_t i =0;
for(i=0;i<32*32;i++)
{
B=(*pSrc) & 0x1F;//000BBBBB
G=((*(pSrc+1) << 3 ) & 0x38) + ((*(pSrc) >> 5 ) & 0x07) ;//得到00GGGGGG
R=(*(pSrc+1) >> 3 ) & 0x1F; //得到000RRRRR
*(p888out+0)=(( B * 527 + 23 ) >> 6)^0x80;
*(p888out+1)=(( G * 259 + 33 ) >> 6)^0x80;
*(p888out+2)=(( R * 527 + 23 ) >> 6)^0x80;
pSrc += 2;
p888out += 3;
}
}
复制代码初始化模型,并运行
if (MODEL_Init() != 0)
{
printf("Failed initializing model\r\n");
for (;;) {}
}
uint8_t* inputData = MODEL_GetInputTensorData(&inputDims, &inputType);
uint8_t* outputData = MODEL_GetOutputTensorData(&outputDims, &outputType);
printf("init OK %d.%d.%d\r\n",inputDims.data[2], inputDims.data[1], inputDims.data[3]);
while (1)
{
if(ov_img_flag == 1)
{
uint8_t *buf = 0;
buf = inputData;
Rgb565StridedToRgb888((uint8_t*)IMG_RGB565_32x32_BUFF_ADDR, buf);
mode_run_ms_count = 0;
MODEL_RunInference();
uint32_t mode_run_ms = mode_run_ms_count;
MODEL_ProcessOutput(outputData, &outputDims, outputType, mode_run_ms);
ov_img_flag = 0;
}
}
复制代码【演示】
空识别
识别船
识别狗
识别猫
识别车
识别飞机
识别鹿
【后记】
不知道为啥一些代码插入就会崩溃,所以一些代码就没有贴出来。