| 
 
| 本帖最后由 b8hqQHaWdEN1 于 2025-5-5 01:55 编辑 
 【概述】
 “ESP32-S3 AI摄像头”模块是一款基于ESP32-S3的开发板,搭载了一个OV3660摄像头,集成了边缘AI处理能力的多功能开发平台,具备强大的神经网络计算能力,本项目就以该摄像头为核心,展示一下该摄像头强大的图像采集和边缘轮廓检测能力。
 【项目来源】
 本项目的灵感来源于路边的烧烤摊,在有一天吃夜宵时,贴主突发奇想,将”ESP32-S3 AI摄像头模块”的边缘轮廓检测用于结账时数签子,这样就可以脱离人工计数的误差,进一步解放双手,实现自动化建设,但是,该项目不仅仅只能用于数签子,还可以用于所有的同类计数识别,也可以进一步优化,实现多个种类同时识别的功能。
 【功能点】
 本项目分为设备端(“ESP32-S3 AI摄像头”)和客户端(电脑python),原理如下:
 1. 设备端:以“ESP32-S3 AI摄像头”为核心,连接网络获取ip地址并建立Web服务器,通过摄像头采集JPEG图像上传到该ip地址服务器。
 2. 客户端:通过访问相应URL获取图像数据,将图像数据解码为OpenCV图像格式-灰度图像-边缘检测-绘制轮廓,在窗口显示实时图像和边缘图像。通过按键实现计数的功能。
 【未来展望】
 目前该项目是通过摄像头采集数据发送至电脑,后续将移植到摄像头本地运行,在功能方面,不仅可以添加集成例如颜色识别的功能,另该项目更加智能化,也可以添加代码变量,统计各项数据,进一步完善该作品。
 【功能实现】一.准备工作
 
 设备端(使用Arduino ide开发环境):
 1.下载Arduino IDE,下载esp32主板,这部分可以在产品维库中实现,因此不在赘述。
 2.配置好该开发板参数,项目-导入库-管理库-下载好“WiFi”“WebServer”两个库文件。
 
 客户端(电脑运行python开发环境):1.打开python代码,下载numpy和opencv-py两个库
 2.在你的python开发环境输入
 “pip install numpy”
 ”Pip install opencv-python“
 回车并下载,
 至此准备工作已全部完成。
 
 
 二.代码实现
 
 准备工作结束后就可以复制如下代码粘贴到Arduion ide中:
 
 复制代码#include <WiFi.h>
#include <WebServer.h>
#include <esp_camera.h>
// ================= 用户配置区域 =================
const char* ssid = "U123";    //替换你的wifi
const char* password = "88888888";  //替换你的密码
// 摄像头引脚配置
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     5
#define Y9_GPIO_NUM       4
#define Y8_GPIO_NUM       6
#define Y7_GPIO_NUM       7
#define Y6_GPIO_NUM       14
#define Y5_GPIO_NUM       17
#define Y4_GPIO_NUM       21
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM       16
#define VSYNC_GPIO_NUM    1
#define HREF_GPIO_NUM     2
#define PCLK_GPIO_NUM     15
#define SIOD_GPIO_NUM     8
#define SIOC_GPIO_NUM     9
const framesize_t FRAME_SIZE = FRAMESIZE_QVGA;  // 320x240
const int JPEG_QUALITY = 15;                    // 质量 (0-63)
const int FB_COUNT = 3;                         // 帧缓冲区数量
// ==============================================
WebServer server(80);
void setupCamera() {
  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;
  // 自适应配置
  if(psramFound()){
    config.frame_size = FRAME_SIZE;
    config.jpeg_quality = JPEG_QUALITY;
    config.fb_count = FB_COUNT;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 15;
    config.fb_count = 1;
  } 
  // 初始化摄像头
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("摄像头初始化失败: 0x%x", err);
    ESP.restart();
  }
  // 图像方向修正
  sensor_t *s = esp_camera_sensor_get();
  s->set_vflip(s, 1);    // 垂直翻转(0关闭1开启)
  s->set_hmirror(s, 1);  // 水平镜像(0关闭1开启)
}
void setupWiFi() {
  WiFi.begin(ssid, password);
  WiFi.setSleep(false);
  
  Serial.print("正在连接WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  
  Serial.println("\nWiFi已连接");
  Serial.print("访问地址: http://");
  Serial.println(WiFi.localIP());
}
void handleJPG() {
  camera_fb_t *fb = esp_camera_fb_get();
  if(!fb) {
    server.send(500, "text/plain", "Camera Error");
    return;
  }
  WiFiClient client = server.client();
  
  // 构建完整HTTP响应
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: image/jpeg\r\n";
  response += "Content-Length: " + String(fb->len) + "\r\n";
  response += "Connection: close\r\n\r\n";
  
  // 分块发送数据
  client.print(response);
  client.write(fb->buf, fb->len);
  esp_camera_fb_return(fb);
}
void setup() {
  Serial.begin(115200);
  delay(1000);  // 等待串口初始化
  
  setupCamera();
  setupWiFi();
  // 路由设置
  server.on("/", HTTP_GET, [](){
    server.sendHeader("Location", "/jpg");
    server.send(302, "text/plain", "");
  });
  
  server.on("/jpg", HTTP_GET, handleJPG);
  
  server.begin();
  Serial.println("HTTP服务器已启动");
}
void loop() {
  server.handleClient();
  delay(2); 
}</font>
 
 步骤如下
 设备端:
 1.在Arduino IDE中选择esp32-s3主板及其串口
 2.File->Examples->ESP32->Camera->CameraWebServer示例
 3.使用下面的代码替换CameraWebServer中的代码,只要替换主程序即可
 (注意:需要填入WIFI账号密码)
 4.上传程序,静等连接WiFi,打开串口监视器返回IP地址(注:电脑和主板需在同一局域网中)
 5.打开浏览器,在Web地址中粘贴获取的IP地址,刷新就可以查看摄像头获取的图片。
 
  
  
 客户端:
 
 复制代码import cv2  
import urllib.request
import numpy as np
url = 'http://192.168.0.106/jpg'  # 获取的esp32-s3 ai的ip地址
# 创建显示窗口
cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE)
while True:
    try:
        # 获取图像数据
        img_resp = urllib.request.urlopen(url)
        imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)
        img = cv2.imdecode(imgnp, -1)
        
        # 如果图像为空则跳过后续处理
        if img is None:
            continue
            
        # 图像处理流程
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(gray, (11, 11), 0)
        canny = cv2.Canny(blurred, 30, 150)
        dilated = cv2.dilate(canny, (1, 1), iterations=2)
        contours, _ = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        # 绘制轮廓
        cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
        
        # 显示结果
        cv2.imshow("Edge Detection", canny)
        cv2.imshow("Live Feed with Contours", img)
        
        # 按键处理
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break
        elif key == ord('a'):
            print(f"检测到轮廓数量: {len(contours)}")
            
    except Exception as e:
        print(f"发生错误: {str(e)}")
        break
cv2.destroyAllWindows()</font>
 
 1.打开python开发环境,复制以上代码并粘贴,修改IP为串口监视器获取的IP地址
 2.屏幕上显示实时图像和边缘检测图像
 3.按下键盘的“Q”键退出程序,按下“A”键检测检测的边缘数量。
 
 
  
 
 
 
 
 
 | 
 | 
|  | 
|
|  | 
|  |  |