前一段时间搞到了一个Seed的ESP32-S3-Xiao的开发板,也是使用过了Edge impulse平台训练过模型并且部署到这了这个开发板上实现了图像识别分类。但是由于那个活动是参加另一个平台的,所以没有办法直接搬过来。不过如果大家感兴趣的话我可以重新再做一遍更新一下数据集然后重新写一遍帖子。 在使用Edge impulse的时候是比较傻瓜式操作的,通常我们也并不需要关注实现的细节,其所有的训练过程直接变成了一个完全的黑盒什么都看不到了。 我最近就是想着直接使用官方的https://github.com/espressif/esp-tflite-micro 来重新训练模型并且在ESP-IDF的环境下运行。 那么由于是图像的分类,那么首要做的一件事就是读取摄像头的输出。

最初版本的Ov2640摄像头已经被代替了,更换成了更新的OV3660。 这个摄像头在Arduino上进行驱动的话是一件非常简单的事情,在IDF的环境下稍微复杂了那么一点点。本文将会介绍如何在IDF的环境下通过ESP32-CAMERA这个库来把摄像头读取到数据,并且把图片的输出为JPEG格式,并且通过BASE64进行编码输出。同时对Base64格式的数据进行解码来获取到原始的图像。
1- 首先在任何一个的项目中注册对应的驱动组件
espressif/esp32-camera
2- 进入到对应的example的文件夹下

3- 代码中我们需要关注的文件一共有三个,分别是PIN的定义文件、Cmakelist的编译文件、和take_pic.c (下述统称main.c) 文件。
在camera_pinout.h中已经定义好了所有的PIN,在.h文件在最下方我们可以看到xiao的摄像头pin也已经被定义好了。
// ESP32S3 (XIAO) #ifdef BOARD_ESP32S3_XIAO #define CAM_PIN_PWDN -1 #define CAM_PIN_RESET -1 //software reset will be performed #define CAM_PIN_VSYNC 38 #define CAM_PIN_HREF 47 #define CAM_PIN_PCLK 13 #define CAM_PIN_XCLK 10 #define CAM_PIN_SIOD 40 #define CAM_PIN_SIOC 39 #define CAM_PIN_D0 15 #define CAM_PIN_D1 17 #define CAM_PIN_D2 18 #define CAM_PIN_D3 16 #define CAM_PIN_D4 14 #define CAM_PIN_D5 12 #define CAM_PIN_D6 11 #define CAM_PIN_D7 48 #endif
4- 在main.c 中打开对应的宏定义即可启用对应的pin

5- 下述代码为修改后的打印图片的代码
void app_main(void)
{
#if ESP_CAMERA_SUPPORTED
if (ESP_OK != init_camera())
{
return;
}
#if defined(CONFIG_CAMERA_AF_SUPPORT) && CONFIG_CAMERA_AF_SUPPORT
// Initialize autofocus if configured and supported by the sensor.
// In menuconfig: Component config → Camera configuration → Enable autofocus support
maybe_init_autofocus();
#endif
while (1)
{
camera_fb_t *pic = esp_camera_fb_get();
// use pic->buf to access the image
// 输出图片数据(Base64格式)
print_image_base64(pic);
esp_camera_fb_return(pic);
vTaskDelay(10000 / portTICK_RATE_MS);
}
#else
ESP_LOGE(TAG, "Camera support is not available for this chip");
return;
#endif
}原本代码中并没有print_image_base64的函数,而是一个打印图片原始数组大小的方法。为了直接打印图片的base64格式方便我们进行查看我们还需要做两处修改。
(一)修改摄像头的图片大小和格式

这里支持很多种格式和大小。我这里为了每次打印的base64的大小,就修改为了240*240来节省空间。
(二)增加mbedtls库的支持。用来打印base64
idf_component_register(SRCS take_picture.c PRIV_INCLUDE_DIRS . PRIV_REQUIRES nvs_flash esp_psram mbedtls)
然后在main.c 中加入一个打印函数用于打印base64
// Base64编码函数 - 使用 mbedTLS 分块转换后直接输出到串口
static void print_image_base64(camera_fb_t *pic)
{
if (!pic || !pic->buf || pic->len == 0)
{
ESP_LOGE(TAG, "Invalid picture data");
return;
}
enum
{
BASE64_INPUT_CHUNK_SIZE = 57,
BASE64_OUTPUT_CHUNK_SIZE = 77,
};
char base64_buf[BASE64_OUTPUT_CHUNK_SIZE] = {0};
for (size_t offset = 0; offset < pic->len; offset += BASE64_INPUT_CHUNK_SIZE)
{
size_t input_len = pic->len - offset;
if (input_len > BASE64_INPUT_CHUNK_SIZE)
{
input_len = BASE64_INPUT_CHUNK_SIZE;
}
size_t output_len = 0;
int ret = mbedtls_base64_encode((unsigned char *)base64_buf,
sizeof(base64_buf),
&output_len,
pic->buf + offset,
input_len);
if (ret != 0)
{
ESP_LOGE(TAG, "Base64 encode failed: %d", ret);
return;
}
base64_buf[output_len] = '\0';
printf("%s\n", base64_buf);
}
}当然也不要忘记引入header
#include "mbedtls/base64.h"
6 - 编译和烧录代码。
如果一切正常串口将开始打印base64的数据,我们可以将这个数据复制出来,找到任何一个base64的解码网站进行解码。得到的图片如下所示。
上图为我的手指。
对应的base64如下
data:image/png;base64,/9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAwICQsJCAwLCgsODQwOEh4UEhEREiUaHBYeLCYuLSsm KikwNkU7MDNBNCkqPFI9QUdKTU5NLzpVW1RLWkVMTUr/2wBDAQ0ODhIQEiMUFCNKMioySkpKSkpK SkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkr/xAAfAAABBQEBAQEB AQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEH InEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFla Y2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbH yMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQID BAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJ IzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1 dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY 2dri4+Tl5ufo6ery8/T19vf4+fr/wAARCADwAPADASEAAhEBAxEB/9oADAMBAAIRAxEAPwDn1qQU gHU8CgAAp+KAE20YoGJijbQUGKKAEpCKAGUlAiN60bNMR0yGWaKCRtRmgBKaaAI2qBqQDMUYoGNx TcUxEgp4pFjxUlAC0AUxj8UmKQBtoxQMQim0hiYptADDTaYER5cCtmBcRimZskAprUCG0wigBuKM UAQvUDUhBikxQMbTKYiQCnhaRZJTxTAMUCgY8U7FAwxRikA0imYpFBTDQIYajNMBsA3TVtoPlpmb HUw0CG4puKAENNNAED1FikAU00xDDTKAJkqSkWKKkAoAdijbTGJinigY7FIaQxpplIYlNNAERqJz xTESacu581sCmZsGoxQIQ0ygBhpjUCIGptIYhphpiI6bSGTgUtBQtPVqBj91OoGFAoGSCg0AMNR0 hhTGoAjNVpzTJZoaZHhM1ogUyBCOaXFAhppCKBEbCo2FAyBqYaQDDTTQIYabTGXBTqChcU0rSGJi ng0FC0tAx605qAGUykAlMNAEbVSP7yUCmQzes0xGKtAUyBtDUAMooAaahegCu1R0ARtTKQDTSUAX KdmgsKWgY4Cl20DGmlApFEgpWpiGUw0gENNNAFO6l2jFN09N8maozZ0Ea4FTUEiYprCgBNtJQAxq ryGgCGmNSAhao6AEpKYF/FIVpFhinCgodRQMMUopDHCgmmIZSUgENQyttU0CMmR/MetfS4qog2FF SigkTFJigBMUw0ARSmqMjc0DG5pjmkBAzUzNIAzRTEaGKKCxaKCh1FAxaKQwpDQA3NFAhrVnXsvY UEsqwrl66TT49qCqIL4FSAUCCm4oAaajNAFabpVJ+tIYlQymgCAmkpAGaKYGrRimUGKMUih1FAwp KQwppoASigRBcSBFrJbLvmmZstWUWXrobZcCmItinUCEooAY1R4oAglWqcgpDIDUL0hkeKSkAlJT JNelpli0tBQ00mKRQtJQAlFACUxmxQIx7+fc2BUMD81RmzZ05MmtuNcUElgUtABimmgBpFMoAhkq jN1pMZWNMNIYw1GaBDTTaANwUmKZQYpKCgopDEooGNopAIaz76TatMlmO5yamtxzVGZ0empwK1wK BEgpaYBSUgEIphoArTdKzpzSYyvQakZGTTTTENNMIpgbVLQWJmkpDEooKEpaAGUUDGtWPfyZbFBn Iz261es1yRTIOmskworQWmIeOtFAxM0tAhDUbUAVpulZ8opFEW2ompAR0lADaSmI2qKZQ2ikUJSU hhSUFCUlAEU7bUJrCmO5iaZlIg6tWtp6ZIpknSWq4FWqBDxRigBhFOFAxGqFqBFaWqr0mMhYVEwp DIyKYRQIbS4oA2KSmUNooKEpKRQGmmkMSloEUNQk+XFZBqjJjU5et7TU6UxG9CvFT7aBD1paAGkU lAxGqJqBFSaqp60ihtMIpCI2FRsKAGYpcUwNWkpljDRUlBRQMbSUhi4pkjYFMRi3Um9zVY1RiOtx mSuj05KBGxHUtAD1paAGmmUDGGmGgRWmFUn60ihmaQmgRHTTSATFIaYjRzSUGgUlIoWkpDG0Uxga pXsu1KCGZJphqjMnsV+eumsV4oEaC08daBktFAhDTKAGGmGgCCTpVGakMgzRSAbS4pgBFRtQIv0U GgUlIoKSkMbS0ARuax7uXfJTREiCmnpVGZd01a6O2GBQBdSpBTAeKKQAajNADDTCKAIZelZ81SMh Ap2KQCUuKoBDUTUCLtFI0FpKChKbQMTNFICreSbUrI6mqRnIWkxmmSaunR8CtyDpQIuDpTxQAop1 ABTTQBGabQBBKKpSrUsZBiigYlLTJGmo2oAtUUGgUUhjc02goKRjikBkXsu+Sq61Rkx1PjGaYjZs kwBWrGKBFoU6mA9aTNIB1I1AERptAET1VkWkMrstMxSASlpiGtTKBE2aM0jUTNGaBiUlIoWq13Ls joEzHJzTxVmQtTQjkUAbtmvArQWgROKdQA6koAeDSMaAIjTaAI2qJhQBC61CVpAMIptADKZQBLRQ aCUUhhRSGNJ4rI1CfLYpiZVB4qRaozH1ZtuWpAb9oOBVxRTETUtACig0ALSGgBpplADTTGoArvUT UgGGozQBGabQBJRQWFJUlBRQMr3cvlx1gyPuamiGIGqzApfpTJHMau2Q5pgb9qOKtrQIlooAWloA WmmgBtNNADDTGoArvUDGkAzNMoAaaZQIdTqRoFJSKEoNAGdqBylZNUSNqxaz+XuHY0CJF+Y5rVsV oEbcHC1YFMRIDS0AOooAWkoAaajJoENppoGV5KrPSAjpKBDTTKAFzTs0jUXNNzQMKRjSAz7/AP1d ZJpkDN1OFMRah6ityxWgRrx9KnFMBRUlAADTqBCUUDGGozQIbTTQBG9VpBSAhIpKBjDTKQhtLmmb C5p1IBaaaQjO1I8VksapEiU9aBFu35YV0NkKYjRSphQIeKU0AIDTs0AFJmgBpqM0ANppoAYaiegC EimYpARtUdADKWg1Fp9SMWmNQIytTas05zVEiDpzTx96lqSXrMZkFdHaVQF5KkFAh4pTQA0U+gBD Tc0ANNMNAxKaaBDDTDQBEaYaQiNqjNAxmKdtoNAxTqQDaY1AGNftmSqNUSANSr1pCNHT/v10NtxT AuLTxQIkFFACUZoAKaaAG000AJTaBDDTDQAymUARmmGgBAKU0jQbRmkMbUbnigDIuh81UW4piEBq VDTJZq6aPmrfgoEWlp9AD6KAEooAM00mgBKaaAGmmk0CGk0wmgYw0ygQw0w0ALSGkaDKSkMKgkoA oyCqMyc0xEQqROtBBr6YK3oaALC0+mA6nUAJSUCEplAwppoAYaaaAGE000AMNMNAhtNNAH//2Q==
总结
本文主要是对ESP32-S3xiao的摄像头在IDF的环境下进行驱动,并且将图片进行编码从而输出base64格式并且在浏览器完成图片内容的转换。图片大小的缩放可以更好的适配后续的tensorflow CNN的输入大小。
我要赚赏金
