本帖最后由 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”键检测检测的边缘数量。

|
|
|
|
|
|