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

马肤

温馨提示:这篇文章已超过472天没有更新,请注意相关的内容是否还可用!

摘要:在半小时内,成功实现了Esp32-Cam模型的训练和图像识别。通过高效的算法和优化的计算资源,实现了快速模型训练。利用Esp32-Cam的摄像头功能,获取图像数据并进行识别,展示了出色的性能和准确性。这一过程为基于Esp32-Cam的图像识别应用提供了便捷、高效的解决方案。

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 
                //
                // 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模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第1张

                工具→串口监视器,然后按下esp32-cam的复位键

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第2张

                复制网址在网页打开,即可看摄像头实时内容了

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第3张

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

                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的视频流例程差不多。

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第4张

                视频窗口设这么小是为了让视频更加流畅。

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

                训练环境是Python,我这边推荐Anaconda

                简单介绍就是:数据可视化+JupyterNotebook+Spyder

                下载用不了多长时间的,然后我们只需要用其中的IDE:Spyder

                下载好之后安装everywhereml包,打开Anaconda Powershell Prompt输入以下指令,already表示包已经安装好了

                pip install everywhereml>=0.2.19
                

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第5张

                步骤1、新建Spyder工程

                project->new project

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第6张

                然后把学习训练模型的Python工程解压添加到工程里,点击获取Python工程

                然后打开Spyder软件如图显示,左边工程文件栏目里就会显示Python工程,此外派上用场的还有交互界面和数据可视化显示界面

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第7张

                步骤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然后回车,如下图所示

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第8张

                之后会显示提示拍了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) 
                

                打开对应文件夹就会发现里边存了拍下来的图片数据

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第9张

                同样的,我训练了pen、napkin

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第10张

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第11张

                如果不想添加了,不用输入直接回车

                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获取了纸巾、笔、空白的情况下各一千多张图片作为数据支撑

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第12张

                首先对图片进行灰化

                在交互界面执行

                image_dataset = image_dataset.gray().uint8()
                

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

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

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第13张

                然后使用定向梯度直方图算法进行处理

                定向梯度直方图( 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()
                

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第14张

                接着输出由特征向量组成的数据集

                print(pipeline)
                

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第15张

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

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

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第16张

                可以直观的看到,这3个类(none、napkin、pen)的聚集性质良好,但在某种程度上彼此是有混合的情况。

                使用降维算法进一步优化

                使用的降维算法是统一流形逼近与投影(Uniform Manifold Approximation and Projection,简称UMAP)

                feature_dataset.plot.umap()
                

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第17张

                分析点聚集性质可知,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)
                

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第18张

                现在,我们已经训练并且建好模型了

                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 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文件复制到工程里边)

                半小时内实现Esp32-Cam模型训练和图像识别,Esp32-Cam模型快速训练与图像识别实现 第19张

                (3)烧录到Esp32-Cam


0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码