半小时内实现Esp32-Cam模型训练和图像识别

2023-05-16

Esp32-Cam图像识别

  • 一、网页显示视频流
    • 1、Linux式例程
    • 2、MicroPython式例程
      • 步骤1、下载Thonny
      • 步骤2、烧录Esp32-Cam固件
      • 步骤3、运行相应代码
    • 3、Arduino式例程
      • 步骤1、下载Arduino
      • 步骤2、安装Esp32-Cam库
      • 步骤3、选择例程
      • 步骤4、查看运行结果
  • 二、半小时内实现图像识别
    • 1、网页视频流
    • 2、通过视频流采集目标并训练
      • 步骤1、新建Spyder工程
      • 步骤2、训练数据获取
      • 步骤3、数据处理并建立模型
    • 3、生成代码移植到Esp32-Cam
      • (1)将HOG和RF算法转换为可以在 Esp32-cam 上运行的C++代码
      • (2)创建Arduino项目工程
      • (3)烧录到Esp32-Cam

这个项目可以让你在半个小时内实现模型训练和图像识别,非常简单。
开始前先放效果视频点击这里

一、网页显示视频流

现成资源有很多,只要稍微找下然后把程序烧录到Esp32-Cam都可以实现该功能。详细内容前往学习即可,此处不赘述。

1、Linux式例程

可以学习安信可官网的例程,权威。点击前往
教程很详细,有Linux基础的兄弟可以尝试一下,否则就别在这个上面折腾了(比如vim编辑器使用、shell脚本使用、linux配置等,都很费时间,而且寡人也没尝试成功)

2、MicroPython式例程

这种方式是让Esp32-Cam具备python环境,能够运行py文件。点击前往

步骤1、下载Thonny

下载地址:https://thonny.org/

步骤2、烧录Esp32-Cam固件

使用Thonny如果烧录固件后无法显示boot.py文件的话应该是底板有问题,可以去买指定的相应底板,但其实使用USB转ttl,杜邦线对应接5V、GND、TXD和RXD就可以了。

步骤3、运行相应代码

import socket
import network
import camera
import time


# 连接wifi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
    print('connecting to network...')
    wlan.connect('dongfeiqiu', 'wangmingdong1225')
    
    while not wlan.isconnected():
        pass
print('网络配置:', wlan.ifconfig())
 
 
# 摄像头初始化
try:
    camera.init(0, format=camera.JPEG)
except Exception as e:
    camera.deinit()
    camera.init(0, format=camera.JPEG)


# 其他设置:
# 上翻下翻
camera.flip(1)
#左/右
camera.mirror(1)

# 分辨率
camera.framesize(camera.FRAME_HVGA)
# 选项如下:
# FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240
# FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA
# FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD
# FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA
# FRAME_P_FHD FRAME_QSXGA
# 有关详细信息,请查看此链接:https://bit.ly/2YOzizz

# 特效
camera.speffect(camera.EFFECT_NONE)
#选项如下:
# 效果\无(默认)效果\负效果\ BW效果\红色效果\绿色效果\蓝色效果\复古效果
# EFFECT_NONE (default) EFFECT_NEG \EFFECT_BW\ EFFECT_RED\ EFFECT_GREEN\ EFFECT_BLUE\ EFFECT_RETRO

# 白平衡
# camera.whitebalance(camera.WB_HOME)
#选项如下:
# WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME

# 饱和
camera.saturation(0)
#-2,2(默认为0). -2灰度
# -2,2 (default 0). -2 grayscale 

# 亮度
camera.brightness(0)
#-2,2(默认为0). 2亮度
# -2,2 (default 0). 2 brightness

# 对比度
camera.contrast(0)
#-2,2(默认为0).2高对比度
#-2,2 (default 0). 2 highcontrast

# 质量
camera.quality(10)
#10-63数字越小质量越高

# socket UDP 的创建
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)

try:
    while True:
        buf = camera.capture()  # 获取图像数据
        s.sendto(buf, ("192.168.31.53", 9090))  # 向服务器发送图像数据
        time.sleep(0.1)
except:
    pass
finally:
    camera.deinit()

3、Arduino式例程

这个也是我发现最简单的实现例程,而且资源也多,涉及的语言主要是C++。点击前往

步骤1、下载Arduino

下载地址:点击前往

步骤2、安装Esp32-Cam库

方法一:在IDE安装。
(1). 文件 → 首选项→附加开发板管理器网址,修改网址为

https://arduino.esp8266.com/stable/package_esp8266com_index.json
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

(2). 工具 → 开发板 → 开发板管理器,搜索esp32,点击安装即可
方法二:github下载zip压缩包作为库
下载地址:点击前往
下载zip压缩包完成后,项目 →包含库 →添加.ZIP库

步骤3、选择例程

工具 →开发板 →esp32 →AI Thinker ESP32-CAM
在如下位置里边填充wifi和密码

const char* ssid = "Your wifi name";
const char* password = "wifi password";

完整代码截取如下

#include "esp_camera.h"
#include <WiFi.h>

//
// WARNING!!! Make sure that you have either selected ESP32 Wrover Module,
//            or another board which has PSRAM enabled
//

// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER

#include "camera_pins.h"

const char* ssid = "Your wifi name";
const char* password = "wifi password";

void startCameraServer();

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();
  //initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1);//flip it back
    s->set_brightness(s, 1);//up the blightness just a bit
    s->set_saturation(s, -2);//lower the saturation
  }
  //drop down frame size for higher initial frame rate
  s->set_framesize(s, FRAMESIZE_QVGA);

#if defined(CAMERA_MODEL_M5STACK_WIDE)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  startCameraServer();

  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(10000);
}

步骤4、查看运行结果

在这里插入图片描述

工具→串口监视器,然后按下esp32-cam的复位键
在这里插入图片描述
复制网址在网页打开,即可看摄像头实时内容了
在这里插入图片描述

二、半小时内实现图像识别

1、网页视频流

和前面的Arduino例程相似,但包含的库不是官方库,而是这个:点击这里
下载该zip库后在IDE操作包含该库,然后复制下面代码作为一个新工程ino文件。注意:要配置自己的板件,然后改成自己的wifi和密码

#include "eloquent.h"
#include "eloquent/networking/wifi.h"
#include "eloquent/vision/camera/esp32/webserver.h"
// 把 'm5wide' 替换成自己的模块,
// 支持的模块有 'aithinker', 'eye', 'm5stack', 'm5wide', 'wrover'
#include "eloquent/vision/camera/aithinker.h"//我用的是aithinker
void setup() {
    Serial.begin(115200);
    delay(2000);
    camera.jpeg();
    camera.qqvga();
    // 改成自己的wifi和密码
    while (!wifi.connectTo("Abc", "12345678"))
        Serial.println("Cannot connect to WiFi");
    while (!camera.begin())
        Serial.println("Cannot connect to camera");
    webServer.start();
    Serial.print("Camera web server started at http://");
    Serial.println(WiFi.localIP());
}
void loop() {
    // do nothing
}

编译烧到esp32-cam板子上后打开串口监视器,获取网址(我的是192.168.1.103),然后在网页打开即可,和常规Arduino的视频流例程差不多。
在这里插入图片描述
视频窗口设这么小是为了让视频更加流畅。

2、通过视频流采集目标并训练

训练环境是Python,我这边推荐Anaconda
简单介绍就是:数据可视化+JupyterNotebook+Spyder
下载用不了多长时间的,然后我们只需要用其中的IDE:Spyder
下载好之后安装everywhereml包,打开Anaconda Powershell Prompt输入以下指令,already表示包已经安装好了

pip install everywhereml>=0.2.19

在这里插入图片描述

步骤1、新建Spyder工程

project->new project
在这里插入图片描述
然后把学习训练模型的Python工程解压添加到工程里,点击获取Python工程
然后打开Spyder软件如图显示,左边工程文件栏目里就会显示Python工程,此外派上用场的还有交互界面和数据可视化显示界面
在这里插入图片描述

步骤2、训练数据获取

复制以下代码到交互界面并回车,从视频流中截取目标图片作为模型数据支撑

from logging import basicConfig, INFO
from everywhereml.data import ImageDataset
from everywhereml.data.collect import MjpegCollector
# 给将要存放数据的文件夹命名
base_folder = 'Images_Data'
# 视频流显示的那个网页地址
IP_ADDRESS_OF_ESP = 'http://192.168.1.103'
basicConfig(level=INFO)
try:
    image_dataset = ImageDataset.from_nested_folders(
        name='Dataset', 
        base_folder=base_folder
    )
except FileNotFoundError:
    mjpeg_collector = MjpegCollector(address=IP_ADDRESS_OF_ESP)
    image_dataset = mjpeg_collector.collect_many_classes(
        dataset_name='Dataset', 
        base_folder=base_folder,
        duration=30
    )
print(image_dataset)

然后就会弹出让你给创建的类命名,我先什么都不识别所以命名none然后回车,如下图所示
在这里插入图片描述
之后会显示提示拍了1272张图作为模型训练基础,并询问该类是否ok

INFO:root:Captured 1272 images
Is this class ok? (y|n)

接着输入y回车,如果是第一次的话会提示建立文件夹Images_Data存数据

INFO:root:creating D:\Esp_Cam\Spyder_Demo\Esp32_Cam\Images_Data folder
INFO:root:creating D:\Esp_Cam\Spyder_Demo\Esp32_Cam\Images_Data\none folder
Which class are you going to capture? (leave empty to exit) 

打开对应文件夹就会发现里边存了拍下来的图片数据
在这里插入图片描述
同样的,我训练了pen、napkin
在这里插入图片描述
在这里插入图片描述
如果不想添加了,不用输入直接回车

Which class are you going to capture? (leave empty to exit) 
Are you sure you want to exit? (y|n) 

然后输入y回车退出,这时候就会显示所训练的类

ImageDataset[Dataset](num_images=3704, num_labels=3, labels=['napkin', 'none', 'pen'])

步骤3、数据处理并建立模型

步骤2获取了纸巾、笔、空白的情况下各一千多张图片作为数据支撑
在这里插入图片描述
首先对图片进行灰化
在交互界面执行

image_dataset = image_dataset.gray().uint8()

可以在交互界面执行以下代码预览数据处理情况

image_dataset.preview(samples_per_class=10, rows_per_class=2, figsize=(20, 10), cmap='gray')

在这里插入图片描述
然后使用定向梯度直方图算法进行处理
定向梯度直方图( Histogram of Oriented Gradients,简称HOG),该算法是轻量级的很适合Esp32-cam使用。
在交互界面执行以下代码

from everywhereml.preprocessing.image.object_detection import HogPipeline
from everywhereml.preprocessing.image.transform import Resize
pipeline = HogPipeline(
    transforms=[
        Resize(width=40, height=30)#此处的分辨率会影响处理时间和模型建立的准确度,可自行调整
    ]
)
feature_dataset = pipeline.fit_transform(image_dataset)
feature_dataset.describe()

在这里插入图片描述
接着输出由特征向量组成的数据集

print(pipeline)

在这里插入图片描述
如果想看所提取的特征量信息情况,可以绘制配对图(pairplot)直观感受数据

feature_dataset.plot.features_pairplot(n=200, k=8)

在这里插入图片描述
可以直观的看到,这3个类(none、napkin、pen)的聚集性质良好,但在某种程度上彼此是有混合的情况。
使用降维算法进一步优化
使用的降维算法是统一流形逼近与投影(Uniform Manifold Approximation and Projection,简称UMAP)

feature_dataset.plot.umap()

在这里插入图片描述
分析点聚集性质可知,1(none)的模型最理想,0(napkin)和2(pen)的模型相对比较差。
总的来说,也算是能够用来表征我们的数据了。
最后训练分类器完成模型建立
使用的建模方法叫随机森林(Random Forest,简称RF)

from everywhereml.sklearn.ensemble import RandomForestClassifier
for i in range(10):
    clf = RandomForestClassifier(n_estimators=5, max_depth=10)
    train, test = feature_dataset.split(test_size=0.4, random_state=i)
    clf.fit(train)
    print('Score on test set: %.2f' % clf.score(test))
clf.fit(feature_dataset)

在这里插入图片描述
现在,我们已经训练并且建好模型了

3、生成代码移植到Esp32-Cam

(1)将HOG和RF算法转换为可以在 Esp32-cam 上运行的C++代码

HOG算法获取特征向量数据集

print(pipeline.to_arduino_file(
    filename='path-to-sketch/HogPipeline.h',
    instance_name='hog'
))

RF算法训练分类器

print(clf.to_arduino_file(
    filename='path-to-sketch/HogClassifier.h',
    instance_name='classifier', 
    class_map=feature_dataset.class_map
))

这时候就会生成两个.h文件在path-to-sketch/ 目录下

(2)创建Arduino项目工程

ino文件里替换成以下代码

#include "eloquent.h"
#include "eloquent/print.h"
#include "eloquent/tinyml/voting/quorum.h"
// 支撑的有 'aithinker', 'eye', 'm5stack', 'm5wide', 'wrover'
#include "eloquent/vision/camera/aithinker.h"//我用的是aithinker
#include "HogPipeline.h"//Spyder里生成的
#include "HogClassifier.h"//Spyder里生成的
Eloquent::TinyML::Voting::Quorum<7> quorum;
void setup() {
  Serial.begin(115200);
  delay(3000);
  Serial.println("Begin");
  camera.qqvga();
  camera.grayscale();
  while (!camera.begin())
    Serial.println("Cannot init camera");
}
void loop() {
  if (!camera.capture()) {
      Serial.println(camera.getErrorMessage());
      delay(1000);
      return;
  }
  hog.transform(camera.buffer);
  uint8_t prediction = classifier.predict(hog.features);
  int8_t stablePrediction = quorum.vote(prediction);
  if (quorum.isStable()) {
    eloquent::print::printf(
      Serial, 
      "Stable prediction: %s \t(DSP: %d ms, Classifier: %d us)\n", 
      classifier.getLabelOf(stablePrediction),
      hog.latencyInMillis(),
      classifier.latencyInMicros()
    );
  }
  camera.free();
}

找到前面生产的两个.h文件,然后包含进工程里(把两个.h文件复制到工程里边)
在这里插入图片描述

(3)烧录到Esp32-Cam

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

半小时内实现Esp32-Cam模型训练和图像识别 的相关文章

随机推荐

  • AD使用教程 图文并茂 AD2020四层板

    文章目录 整体流程图 xff1a 资源下载 xff1a 自定义快捷键 xff1a xff08 按照个人习惯 xff09 默认快捷键 xff1a 一 软件主页面1 主界面2 Panels面板3 系统设置3 自定义快捷键4 新建工程 二 原理图
  • 【HAL库】HAL库STM32cubemx快速使用

    文章目录 整体框图一 基础工程1 新建工程2 配置RCC3 配置SYS4 工程设置5 生成代码6 keil设置下载 amp 复位 二 必备外设1 目录规范2 LED2 RTC3 USART4 KEY 三 其他外设1 OLED xff08 模
  • 【HAL库】STM32+ESP8266+Onenet+MQTT,极简工程,hal库移植。

    ESP8266 43 Onenet 43 MQTT 1 导入 c h文件 xff08 不再赘述 xff0c 详细见LED部分 xff09 2 Cubemx配置3 修改 c h 文件4 测试 ESP8266通过MQTT协议连接Onenet 从
  • 【HAL库】BMP180气压传感器+STM32,hal库移植

    BMP180气压传感器 43 STM32 1 导入 c h文件 xff08 不再赘述 xff0c 详细见LED部分 xff09 2 Cubemx配置3 修改 h 文件4 测试 将BMP180从标准库移植到HAL库 模拟IIC 极简工程代码如
  • 【硬件】嵌入式板卡硬件电路设计、焊接

    文章目录 嵌入式板卡电路 框图常用焊接工具和焊接操作 框图一 元器件 有极性 1 肖特基二极管2 钽电容3 三极管4 MOS5 LED6 SMAJ5 0CA xff08 TVS管 xff09 8 SRV05 4 xff08 ESD管 xff
  • C语言中的输入输出函数

    一 字符数据输入输出函数 1 putchar xff0c 输出一个字符 include lt stdio h gt int main char cChar1 cChar2 cChar3 cChar4 cChar1 61 39 H 39 cC
  • printf的执行顺序&++i与i++的区别

    问题的由来 xff1a 在学习C语言预处理命令时看到这样一段 https www cnblogs com clover toeic p 3851102 html span class token macro property span cl
  • Traceback (most recent call last): File “/home/myp4/.local/bin/pip“, line 5, in <module> from

    https blog csdn net weixin 41135864 article details 89817343 Traceback most recent call last File home myp4 local bin pi
  • sys.stderr.write(f“ERROR: {exc}”)

    https www cjavapy com article 1701
  • 为什么PBFT需要三阶段

    首先 xff0c 第一阶段是预提议 xff08 pre prepare xff09 xff0c 这一阶段的主要原因是使用领导可以降低通信复杂度 xff0c 但是我对其没了解 xff0c 就不瞎说了 接着是提议 xff08 prepare x
  • 文件的自定义包发送接收

    需求 对一个特定的文件进行分片发送 xff0c 构造数据包 xff0c 发送数据包 xff0c 接收数据包并提取有效数据 xff0c 对数据组合还原为原文件 设计 当前 xff0c 基于socket的网络编程已成为当今不可替代的编程方法 x
  • 阿里云服务器图形化界面

    https blog csdn net qq 43264202 article details 119578968
  • 安卓开放端口

    https blog csdn net weixin 39737831 article details 109965587
  • Ubuntu14.04 支持ESM

    https discourse ubuntu com t ubuntu advantage client 21788
  • 开启关闭ICMP

    echo request http www xoxxoo com index index article id 780 html redirect https blog csdn net weixin 39684454 article de
  • AD使用技巧

    AD快捷键 快捷键要处在英文模式的情况下才可以使用 xff1a AD测量快捷键 xff1a R AD对齐快捷键 xff1a A AD切换单位快捷键 xff1a Q AD改变栅格快捷键 xff1a G AD视图配置快捷键 xff1a L AD
  • 多传感器融合框架搭建

    架构 src include apps xff1a 节点文件 front end node cpp 前端节点data pretreat node cpp 数据预处理节点back end node cpp 后端节点loop closing n
  • 多传感器融合框架-ESKF

    架构 基本同图优化框架差不多 内容简述 数据预处理节点 订阅imu原始数据 xff0c gnss原始数据 xff0c 完成数据时间戳同步 点云畸变补偿发布如下消息 畸变补偿后的点云 synced cloudgnss里程计 synced gn
  • OpenCV笔记4.3

    C 43 43 读取目录下所有文件名称 1 包含头文件 96 span class token macro property span class token directive hash span span class token dir
  • 半小时内实现Esp32-Cam模型训练和图像识别

    Esp32 Cam图像识别 一 网页显示视频流1 Linux式例程2 MicroPython式例程步骤1 下载Thonny步骤2 烧录Esp32 Cam固件步骤3 运行相应代码 3 Arduino式例程步骤1 下载Arduino步骤2 安装