133浏览
查看: 133|回复: 0

[ESP8266/ESP32] ESP32-S3 AI CAM——基于yoloV5的AI安防系统

[复制链接]
本帖最后由 kylinpoet 于 2025-5-6 14:04 编辑

一、项目缘起:
ESP32 S3 + CAM 实在是低成本、高效的安防搭档。本项目通过在esp32上搭建http视频流服务,利用上位机实时获取摄像头的传递数据,进行识别。相应的数据处理在上位机完成。包括使用yolov5的预训练80分类数据进行人体识别,以及通过消息平台进行报警。

二、操作步骤:
1. 视频图传
在 dfrobot 的wiki库里找到并刷入,视频图传演示代码(点击访问),需要注意的是使用 Arduino 1.8版本刷入才行,Arduino 2 会输入失败(留待大佬解决)
  1. #include "esp_camera.h"
  2. #include <WiFi.h>
  3. //
  4. // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
  5. //            Ensure ESP32 Wrover Module or other board with PSRAM is selected
  6. //            Partial images will be transmitted if image exceeds buffer size
  7. //
  8. //            You must select partition scheme from the board menu that has at least 3MB APP space.
  9. //            Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
  10. //            seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well
  11. #define PWDN_GPIO_NUM     -1
  12. #define RESET_GPIO_NUM    -1
  13. #define XCLK_GPIO_NUM     5
  14. #define Y9_GPIO_NUM       4
  15. #define Y8_GPIO_NUM       6
  16. #define Y7_GPIO_NUM       7
  17. #define Y6_GPIO_NUM       14
  18. #define Y5_GPIO_NUM       17
  19. #define Y4_GPIO_NUM       21
  20. #define Y3_GPIO_NUM       18
  21. #define Y2_GPIO_NUM       16
  22. #define VSYNC_GPIO_NUM    1
  23. #define HREF_GPIO_NUM     2
  24. #define PCLK_GPIO_NUM     15
  25. #define SIOD_GPIO_NUM  8
  26. #define SIOC_GPIO_NUM  9
  27. // ===========================
  28. // Enter your WiFi credentials
  29. // ===========================
  30. const char *ssid = "**********";
  31. const char *password = "**********";
  32. void startCameraServer();
  33. void setupLedFlash(int pin);
  34. void setup() {
  35.   Serial.begin(115200);
  36.   Serial.setDebugOutput(true);
  37.   Serial.println();
  38.   camera_config_t config;
  39.   config.ledc_channel = LEDC_CHANNEL_0;
  40.   config.ledc_timer = LEDC_TIMER_0;
  41.   config.pin_d0 = Y2_GPIO_NUM;
  42.   config.pin_d1 = Y3_GPIO_NUM;
  43.   config.pin_d2 = Y4_GPIO_NUM;
  44.   config.pin_d3 = Y5_GPIO_NUM;
  45.   config.pin_d4 = Y6_GPIO_NUM;
  46.   config.pin_d5 = Y7_GPIO_NUM;
  47.   config.pin_d6 = Y8_GPIO_NUM;
  48.   config.pin_d7 = Y9_GPIO_NUM;
  49.   config.pin_xclk = XCLK_GPIO_NUM;
  50.   config.pin_pclk = PCLK_GPIO_NUM;
  51.   config.pin_vsync = VSYNC_GPIO_NUM;
  52.   config.pin_href = HREF_GPIO_NUM;
  53.   config.pin_sccb_sda = SIOD_GPIO_NUM;
  54.   config.pin_sccb_scl = SIOC_GPIO_NUM;
  55.   config.pin_pwdn = PWDN_GPIO_NUM;
  56.   config.pin_reset = RESET_GPIO_NUM;
  57.   config.xclk_freq_hz = 20000000;
  58.   config.frame_size = FRAMESIZE_UXGA;
  59.   config.pixel_format = PIXFORMAT_JPEG;  // for streaming
  60.   //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
  61.   config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  62.   config.fb_location = CAMERA_FB_IN_PSRAM;
  63.   config.jpeg_quality = 12;
  64.   config.fb_count = 1;
  65.   // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  66.   //                      for larger pre-allocated frame buffer.
  67.   if (config.pixel_format == PIXFORMAT_JPEG) {
  68.     if (psramFound()) {
  69.       config.jpeg_quality = 10;
  70.       config.fb_count = 2;
  71.       config.grab_mode = CAMERA_GRAB_LATEST;
  72.     } else {
  73.       // Limit the frame size when PSRAM is not available
  74.       config.frame_size = FRAMESIZE_SVGA;
  75.       config.fb_location = CAMERA_FB_IN_DRAM;
  76.     }
  77.   } else {
  78.     // Best option for face detection/recognition
  79.     config.frame_size = FRAMESIZE_240X240;
  80. #if CONFIG_IDF_TARGET_ESP32S3
  81.     config.fb_count = 2;
  82. #endif
  83.   }
  84. #if defined(CAMERA_MODEL_ESP_EYE)
  85.   pinMode(13, INPUT_PULLUP);
  86.   pinMode(14, INPUT_PULLUP);
  87. #endif
  88.   // camera init
  89.   esp_err_t err = esp_camera_init(&config);
  90.   if (err != ESP_OK) {
  91.     Serial.printf("Camera init failed with error 0x%x", err);
  92.     return;
  93.   }
  94.   sensor_t *s = esp_camera_sensor_get();
  95.   // initial sensors are flipped vertically and colors are a bit saturated
  96.   if (s->id.PID == OV3660_PID) {
  97.     s->set_vflip(s, 1);        // flip it back
  98.     s->set_brightness(s, 1);   // up the brightness just a bit
  99.     s->set_saturation(s, -2);  // lower the saturation
  100.   }
  101.   // drop down frame size for higher initial frame rate
  102.   if (config.pixel_format == PIXFORMAT_JPEG) {
  103.     s->set_framesize(s, FRAMESIZE_QVGA);
  104.   }
  105. #if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
  106.   s->set_vflip(s, 1);
  107.   s->set_hmirror(s, 1);
  108. #endif
  109. #if defined(CAMERA_MODEL_ESP32S3_EYE)
  110.   s->set_vflip(s, 1);
  111. #endif
  112. // Setup LED FLash if LED pin is defined in camera_pins.h
  113. #if defined(LED_GPIO_NUM)
  114.   setupLedFlash(LED_GPIO_NUM);
  115. #endif
  116.   WiFi.begin(ssid, password);
  117.   WiFi.setSleep(false);
  118.   Serial.print("WiFi connecting");
  119.   while (WiFi.status() != WL_CONNECTED) {
  120.     delay(500);
  121.     Serial.print(".");
  122.   }
  123.   Serial.println("");
  124.   Serial.println("WiFi connected");
  125.   startCameraServer();
  126.   Serial.print("Camera Ready! Use 'http://");
  127.   Serial.print(WiFi.localIP());
  128.   Serial.println("' to connect");
  129. }
  130. void loop() {
  131.   // Do nothing. Everything is done in another task by the web server
  132.   delay(10000);
  133. }
复制代码
刷入成功后,我们会在串口中看到wifi连接信息。访问相应地址后,我们会看到以下内容。

ESP32-S3 AI CAM——基于yoloV5的AI安防系统图2ESP32-S3 AI CAM——基于yoloV5的AI安防系统图3
这里要注意下,网址首页打开是视频流的形式,访问 /capture 子页面,是抓取的实时图片。
我们在上位机上用的就是这个子页面。
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图4





2. 基于电脑yoloV5实现

yoloV5的代码,我们主要参考这里的文档(点击访问),但要做一些改变:
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图5
这里主要是判断是否检测到人类,以及为了正确阈值,设置的置信度。
另外还要增加发送消息预警的函数,这里是使用免费微信消息推送服务:server酱,当然你可以使用其它类似服务:
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图6
以下是识别到人类活动后的消息推送:
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图7

参考代码如下:
  1. import cv2
  2. import torch
  3. import time
  4. from yolov5 import YOLOv5
  5. import urllib.request
  6. import numpy as np
  7. import requests
  8. from img_upload import img_upload
  9. url = 'http://192.168.1.43:80/capture'  # ESP32-CAM的IP地址
  10. sendkey = ''
  11. # Load the YOLOv5 model
  12. model_path = "d:/yolov5s.pt"  # 模型路径
  13. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  14. model = YOLOv5(model_path, device=device)
  15. last_alert_time = 0
  16. # 通过server酱发送微信消息推送
  17. def send_alert(title, img):
  18.     url = f"https://sctapi.ftqq.com/{sendkey}.send"
  19.     # 使用Markdown语法在desp中嵌入图片
  20.     image_url = img_upload(img)
  21.     desp = f"![人类检测报警图片]({image_url})"  # 图片需为可访问的URL
  22.     payload = {
  23.         "text": title,
  24.         "desp": desp
  25.     }
  26.     response = requests.post(url, data=payload)
  27.     return response.json()
  28. while True:
  29.     img_resp = urllib.request.urlopen(url)  # 从URL获取图像数据
  30.     img_source = img_resp.read()
  31.     imgnp = np.array(bytearray(img_source), dtype=np.uint8)  # 将图像数据转换为NumPy数
  32.     frame = cv2.imdecode(imgnp, -1)  # 解码JPEG图像数据
  33.     # 记录处理开始时间
  34.     start_time = time.time()
  35.     # 将帧传递给模型进行预测
  36.     results = model.predict(frame, size=640)  # 调整输入图像大小为640x640
  37.     # 遍历检测结果
  38.     for i, det in enumerate(results.pred[0]):
  39.         if det is not None and len(det):
  40.             det = det.unsqueeze(0)
  41.             for *xyxy, conf, cls in det:
  42.                 # 获取类别名称和置信度
  43.                 class_name = results.names[int(cls)]
  44.                 confidence = float(conf)
  45.                 print(f"检测到类别: {class_name}, 置信度: {confidence:.2f}")
  46.                 if class_name == "person" and confidence > 0.5:
  47.                     current_time = time.time()
  48.                     # 检查是否距离上次报警超过5分钟(300秒)
  49.                     if current_time - last_alert_time >= 300: # 5分钟内只报一次警
  50.                         print(f"检测到人类活动,触发报警")
  51.                         send_alert('检测到人类活动,触发报警', img_source)
  52.                         last_alert_time = current_time  # 更新上次报警时间
  53.                 # 如需保存结果,可写入文件
  54.    
  55.     # 获取预测结果并在图像上绘制
  56.     annotated_frame = results.render()  # YOLOv5库中的render方法
  57.     # 记录处理结束时间
  58.     end_time = time.time()
  59.     # 计算帧率
  60.     processing_time = end_time - start_time
  61.     fps = 1 / processing_time
  62.     # 在图像上绘制帧率
  63.     # cv2.putText(annotated_frame[0], f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
  64.     # 提取可写副本
  65.     img_output = annotated_frame[0].copy()
  66.     cv2.putText(img_output, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
  67.     # 显示带有预测结果的帧
  68.     cv2.imshow("YOLOv5 Detection", annotated_frame[0])
  69.     # 打印详细信息到终端
  70.     print(f"Processed frame in {processing_time:.4f} seconds, FPS: {fps:.2f}")
  71.     # 按下 'q' 键退出
  72.     if cv2.waitKey(1) & 0xFF == ord('q'):
  73.         break
  74. # 释放摄像头资源并关闭所有窗口
  75. # cap.release()
  76. cv2.destroyAllWindows()
复制代码

顺便提下,yoloV5的预训练分类如下展示,class 0 是 person,其它可查看以下部分分类信息。完整内容请自行查阅。
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图1


3. 实践过程中的几点思考:

这里重点说明下测试过程中,填的几个坑:
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图8
1). 如上图①所示,示例代码里的模型路径,需要使用绝对路径,否则默认寻找的路径是 %homepath% ,也就是说需要将 pt 文件拷贝到这个目录,也就用户目录如:C:\Users\你的用户名\yolov5s.pt。如果此路径没有这个文件,他会去 https://github.com/ultralytics/y ... oad/v7.0/yolov5s.pt  下载,而这个下载地址有时候是需要特殊网络的!!!

2). 如上图②所示,因为我装的是 GPU 版的torch!!!,这里应该是使用 'cuda:0',而不是实例代码的 'cuda'。

三、安装图
ESP32-S3 AI CAM——基于yoloV5的AI安防系统图9




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail