欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 使用XiaoESP32S3在Arduino环境中实现颜色识别

使用XiaoESP32S3在Arduino环境中实现颜色识别

2025/3/26 9:17:34 来源:https://blog.csdn.net/lyx4949/article/details/146479204  浏览:    关键词:使用XiaoESP32S3在Arduino环境中实现颜色识别

最近在项目开发中,我尝试使用XIAO ESP32S3搭载OV2640摄像头,完成对颜色色块的实时识别。本篇博客将系统性地介绍如何在Arduino环境中使用XIAO ESP32S3实现颜色识别,并分享完整代码。


请添加图片描述

一、硬件准备

1.1 必备硬件

  • XIAO ESP32S3 开发板(带PSRAM)
  • OV2640摄像头模块 (广角 80°)
  • USB数据线
    在这里插入图片描述

二、开发环境搭建

2.1 安装Arduino IDE

  • 下载并安装Arduino IDE(推荐版本:2.2.1)。
  • 打开文件 -> 首选项,在“附加开发板管理器网址”中填写以下地址:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
    点击确定后,到工具 -> 开发板 -> 开发板管理器中搜索esp32,选择esp32 by Espressif Systems进行安装。

2.2 开发板选择与配置

  1. 插入XIAO ESP32S3开发板,打开Arduino IDE。
  2. 工具 -> 开发板中选择XIAO_ESP32S3
  3. 工具配置选项见下图:
    -在这里插入图片描述

三、实现颜色识别的完整代码

以下代码实现了XIAO ESP32S3对红、黄、绿、蓝、紫五种颜色色块的实时识别,并通过IIC接口传输检测结果。
项目结构:

project/
├── src/
│   ├── app_httpd.cpp
│   ├── camera_setting.c
│   ├── color_detection.cpp
│   ├── iic_data_send.cpp
│   └── XIAO_ESP32S3_color_WIFI_5s.ino
├── include/
│   ├── camera_index.h
│   ├── camera_setting.h
│   ├── color_detection.hpp
│   └── iic_data_send.hpp
├── data/
│   └── partitions.csv

3.1 主程序:颜色识别与WiFi热点功能

XIAO_ESP32S3_color_WIFI_5s.ino

#include "camera_setting.h"
#include "color_detection.hpp"
#include "iic_data_send.hpp"
#include "esp_camera.h"
#include <WiFi.h>#define CAMERA_MODEL_XIAO_ESP32S3 // 使用XIAO ESP32S3摄像头
static QueueHandle_t xQueueAIFrame = NULL;
static QueueHandle_t xQueueIICData = NULL;const char* ssid = "ESP123-3";  // 自定义WiFi名称
const char* password = "12345678";  // 自定义WiFi密码void startCameraServer();void setup() {
Serial.begin(115200);
Serial.println();// 创建图像传输队列
xQueueAIFrame = xQueueCreate(2, sizeof(camera_fb_t *)); 
// 创建IIC数据传输队列
xQueueIICData = xQueueCreate(2, sizeof(color_data_t *) * SEND_CLOLOR_NUM);// 注册摄像头任务
register_camera(PIXFORMAT_RGB565, FRAMESIZE_240X240, 4, xQueueAIFrame);
// 注册颜色检测任务
register_color_detection(xQueueAIFrame, NULL, xQueueIICData, NULL, true);
// 注册IIC数据传输任务
register_iic_data_send(xQueueIICData, NULL);// 开启WiFi热点
WiFi.softAP(ssid, password);
startCameraServer();Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}void loop() {
delay(1000);
}

这里我添加了wifi热点模式,连接对应的热点名称(ESP123-3,可以看到摄像头画面,但是因为串口一直在输出,所以画面会很卡顿,请耐心!)

3.2 颜色检测模块

color_detection.cpp
颜色识别算法的主要逻辑是:从摄像头获取图像帧,对图像进行颜色检测,找到每种颜色的最大色块,记录其中心点坐标、宽度和长度信息,最后将识别结果通过队列传递给其他任务。通过这种方式,可以实现实时的颜色识别功能。

#include "color_detection.hpp"
#include "esp_log.h"
#include "esp_camera.h"
#include "dl_image.hpp"
#include "fb_gfx.h"
#include "color_detector.hpp"using namespace std;
using namespace dl;static const char *TAG = "color_detection";static QueueHandle_t xQueueFrameI = NULL;
static QueueHandle_t xQueueEvent = NULL;
static QueueHandle_t xQueueFrameO = NULL;
static QueueHandle_t xQueueResult = NULL;static bool gReturnFB = true;
static int g_max_color_area = 0;
color_data_t color_data[5];/* 颜色阈值 可在此处调整HSV */
vector<color_info_t> std_color_info = {{{151, 15, 70, 255, 90, 255}, 64, "red"},{{23, 34, 70, 255, 90, 255}, 64, "yellow"},{{45, 75, 70, 255, 90, 255}, 64, "green"},{{97, 117, 70, 255, 90, 255}, 64, "blue"},{{130, 155, 70, 255, 90, 255}, 64, "purple"}
};static uint8_t state_value;/* 获取颜色检测的结果 */
static void get_color_detection_result(uint16_t *image_ptr, int image_height, int image_width, vector<color_detect_result_t> &results, uint16_t color)
{int g_max_color_column_index = 0;/* 寻找同色最大色块 */for (int i = 0; i < results.size(); ++i){if (results[i].area > g_max_color_area){g_max_color_area= results[i].area;g_max_color_column_index = i;}switch (color){case COLOR_RED:color_data[0].center_x = (uint8_t)results[g_max_color_column_index].center[0];color_data[0].center_y = (uint8_t)results[g_max_color_column_index].center[1];/* right_down_x - left_up_x  */color_data[0].width = (uint8_t)(results[g_max_color_column_index].box[2] - results[g_max_color_column_index].box[0]);/* right_down_y - left_up_y  */color_data[0].length = (uint8_t)(results[g_max_color_column_index].box[3] - results[g_max_color_column_index].box[1]);break;case COLOR_YELLOW:color_data[1].center_x = (uint8_t)results[g_max_color_column_index].center[0];color_data[1].center_y = (uint8_t)results[g_max_color_column_index].center[1];/* right_down_x - left_up_x  */color_data[1].width = (uint8_t)(results[g_max_color_column_index].box[2] - results[g_max_color_column_index].box[0]);/* right_down_y - left_up_y  */color_data[1].length = (uint8_t)(results[g_max_color_column_index].box[3] - results[g_max_color_column_index].box[1]);break;case COLOR_GREEN:color_data[2].center_x = (uint8_t)results[g_max_color_column_index].center[0];color_data[2].center_y = (uint8_t)results[g_max_color_column_index].center[1];/* right_down_x - left_up_x  */color_data[2].width = (uint8_t)(results[g_max_color_column_index].box[2] - results[g_max_color_column_index].box[0]);/* right_down_y - left_up_y  */color_data[2].length = (uint8_t)(results[g_max_color_column_index].box[3] - results[g_max_color_column_index].box[1]);break;case COLOR_BLUE:color_data[3].center_x = (uint8_t)results[g_max_color_column_index].center[0];color_data[3].center_y = (uint8_t)results[g_max_color_column_index].center[1];/* right_down_x - left_up_x  */color_data[3].width = (uint8_t)(results[g_max_color_column_index].box[2] - results[g_max_color_column_index].box[0]);/* right_down_y - left_up_y  */color_data[3].length = (uint8_t)(results[g_max_color_column_index].box[3] - results[g_max_color_column_index].box[1]);break;case COLOR_PURPLE:color_data[4].center_x = (uint8_t)results[g_max_color_column_index].center[0];color_data[4].center_y = (uint8_t)results[g_max_color_column_index].center[1];/* right_down_x - left_up_x  */color_data[4].width = (uint8_t)(results[g_max_color_column_index].box[2] - results[g_max_color_column_index].box[0]);/* right_down_y - left_up_y  */color_data[4].length = (uint8_t)(results[g_max_color_column_index].box[3] - results[g_max_color_column_index].box[1]);break;default:break;}    }
}static void task_process_handler(void *arg)
{camera_fb_t *frame = NULL;ColorDetector detector;/* 注册颜色信息 */for (int i = 0; i < std_color_info.size(); ++i){detector.register_color(std_color_info[i].color_thresh, std_color_info[i].area_thresh, std_color_info[i].name);}vector<uint16_t> draw_colors = {COLOR_RED,COLOR_YELLOW,COLOR_GREEN,COLOR_BLUE,COLOR_PURPLE,};int draw_colors_num = draw_colors.size();while (true){// printf("center_x:%d\r\n", color_data[3].center_x);if (xQueueReceive(xQueueFrameI, &frame, portMAX_DELAY)){std::vector<std::vector<color_detect_result_t>> &results = detector.detect((uint16_t *)frame->buf, {(int)frame->height, (int)frame->width, 3});for(int i = 0; i < COLOR_NUM; ++i){if(results[i].size() == 0){color_data[i].center_x = 0;color_data[i].center_y = 0;color_data[i].width = 0;color_data[i].length = 0;}else{printf("Color:[%d] \r\n", i);}}for (int i = 0; i < results.size(); ++i){get_color_detection_result((uint16_t *)frame->buf, (int)frame->height, (int)frame->width, results[i], draw_colors[i % draw_colors_num]);}}if (xQueueFrameO){xQueueSend(xQueueFrameO, &frame, portMAX_DELAY);}else if (gReturnFB){esp_camera_fb_return(frame);}else{free(frame);}if (xQueueResult){xQueueSend(xQueueResult, &color_data, portMAX_DELAY);             }          }
}static void task_event_handler(void *arg)
{while (true){}
}void register_color_detection(const QueueHandle_t frame_i,const QueueHandle_t event,const QueueHandle_t result,const QueueHandle_t frame_o,const bool camera_fb_return)
{xQueueFrameI = frame_i;xQueueFrameO = frame_o;xQueueEvent = event;xQueueResult = result;gReturnFB = camera_fb_return;xTaskCreatePinnedToCore(task_process_handler, TAG, 4 * 1024, NULL, 5, NULL, 1);// xTaskCreatePinnedToCore(task_event_handler, TAG, 4 * 1024, NULL, 5, NULL, 0);
}

颜色阈值 可在此处调整HSV
vector<color_info_t> std_color_info = {
{{151, 15, 70, 255, 90, 255}, 64, “red”},
{{23, 34, 70, 255, 90, 255}, 64, “yellow”},
{{45, 75, 70, 255, 90, 255}, 64, “green”},
{{97, 117, 70, 255, 90, 255}, 64, “blue”},
{{130, 155, 70, 255, 90, 255}, 64, “purple”}
};根据摄像头拍摄的画面,调整颜色的HSV阈值,上面的参数分别代表, H_min, H_max, S_min, S_max, V_min, V_max

3.3 在运行窗口打印出检测数值

通过IIC接口,可以将检测结果实时传输到其他模块
iic_data_send.cpp

#include "iic_data_send.hpp"
#include "Wire.h"#define I2C_SLAVE_ADDRESS 0x52static QueueHandle_t xQueueResultI = NULL;
static QueueHandle_t xQueueResultO = NULL;static const char *TAG = "iic_data_send";
static const int sdaPin = 5;
static const int sclPin = 6;
static const uint32_t i2cFrequency = 100000;send_color_data_t send_color_data[5];static uint8_t rec = 0xFF;
static uint8_t send_data[4] = {0};static void iic_receive(int len)
{while(Wire.available()){rec = Wire.read();}  
}static void iic_request()
{/* 发送红色色块数据 */if(rec == 0x00) {send_data[0] = send_color_data[0].center_x;send_data[1] = send_color_data[0].center_y;send_data[2] = send_color_data[0].width;send_data[3] = send_color_data[0].length;}/* 发送绿色色块数据 */else if(rec == 0x01){send_data[0] = send_color_data[1].center_x;send_data[1] = send_color_data[1].center_y;send_data[2] = send_color_data[1].width;send_data[3] = send_color_data[1].length;}/* 发送蓝色色块数据 */else if(rec == 0x02){send_data[0] = send_color_data[2].center_x;send_data[1] = send_color_data[2].center_y;send_data[2] = send_color_data[2].width;send_data[3] = send_color_data[2].length;}/* 发送黄色色块数据 */else if(rec == 0x03){send_data[0] = send_color_data[3].center_x;send_data[1] = send_color_data[3].center_y;send_data[2] = send_color_data[3].width;send_data[3] = send_color_data[3].length;}/* 发送紫色色块数据 */else if(rec == 0x04){send_data[0] = send_color_data[0].id;send_data[1] = send_color_data[1].id;send_data[2] = send_color_data[2].id;send_data[3] = send_color_data[3].id;      }/* 打包发送色块数据 */Wire.slaveWrite(send_data, sizeof(send_data));
}static void task_process_handler(void *arg)
{/* IIC初始化 */Wire.begin((uint8_t)I2C_SLAVE_ADDRESS, sdaPin, sclPin, i2cFrequency);/* 注册接收数据的回调函数 */Wire.onReceive(iic_receive);/* 注册请求数据的回调函数 */Wire.onRequest(iic_request);while (true){if (xQueueReceive(xQueueResultI, &send_color_data, portMAX_DELAY)){printf("center_x: red:%d yellow:%d green:%d  blue:%d  purple:%d\r\n", send_color_data[0].center_x, \send_color_data[1].center_x, \send_color_data[2].center_x, \send_color_data[3].center_x, \send_color_data[4].center_x);}}
}void register_iic_data_send(const QueueHandle_t result_i,const QueueHandle_t result_o)
{xQueueResultI = result_i;xQueueResultO = result_o;xTaskCreatePinnedToCore(task_process_handler, TAG, 5 * 1024, NULL, 5, NULL, 1);
}

四、效果展示

颜色识别:当摄像头检测到红、黄、绿、蓝、紫五种颜色的色块时,可以通过串口打印检测到的色块中心坐标及尺寸。
Web 端实时监控:连接热点“ESP32S3-3”浏览器打开“192.168.4.1”查看实时视频流
在这里插入图片描述
完整程序链接:通过网盘分享的文件:XIAO_ESP32S3_color_WIFI_5s.zip
链接: https://pan.baidu.com/s/1LIpI19jnzQ_ENh_wjTlozw 提取码: lyx4

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词