【ESP32S3 Sense接入阿里云大模型图像理解】

ESP32S3 Sense接入阿里云大模型图像理解

  • [1. 前言](#1. 前言)
    • [1.1 通义千问VL](#1.1 通义千问VL)
    • [1.3 使用本地文件](#1.3 使用本地文件)
    • [1.4 返回结果](#1.4 返回结果)
  • [2. 先决条件](#2. 先决条件)
    • [2.1 环境配置](#2.1 环境配置)
    • [2.2 所需零件](#2.2 所需零件)
  • [3. 核心代码](#3. 核心代码)
    • [3.1 源码分享](#3.1 源码分享)
    • [3.2 源码解析](#3.2 源码解析)
  • [4. 上传验证](#4. 上传验证)
    • [4.1 下载配置](#4.1 下载配置)
    • [4.2 打开串口](#4.2 打开串口)
  • [5. 总结](#5. 总结)

1. 前言

随着人工智能技术的发展,图像理解成为了机器视觉领域的热点话题之一。通过深度学习算法,机器能够识别和理解图像中的内容,为许多应用场景提供了无限可能。本文将介绍如何使用ESP32S3 Sense开发板接入阿里云的大模型服务,实现图像的理解功能。我们将使用ESP32的摄像头模块拍摄照片,并通过阿里云提供的API接口发送图像数据,最后接收并解析API返回的结果。

1.1 通义千问VL

通义大模型官网地址:https://www.aliyun.com/product/bailian?spm=a2c4g.11186623.0.0.46d76d5251FMig

通义千问VL官网地址:https://help.aliyun.com/zh/model-studio/user-guide/vision?spm=a2c4g.11186623.0.0.44481f8fQbOFKb

通义千问VL模型可以根据您传入的图片来进行回答。访问模型广场可以在线体验图片理解能力。

1.3 使用本地文件

您可以参考以下示例代码,通过OpenAI或者DashScope的方式,调用通义千问VL模型处理本地文件。以下代码使用的示例图片为:test.png

python 复制代码
from openai import OpenAI
import os
import base64


#  base 64 编码格式
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")


base64_image = encode_image("test.png")
client = OpenAI(
    # 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
completion = client.chat.completions.create(
    model="qwen-vl-max-latest",
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},
                },
                {"type": "text", "text": "这是什么"},
            ],
        }
    ],
)
print(completion.choices[0].message.content)

1.4 返回结果

bash 复制代码
这是一只飞翔的鹰。鹰是一种猛禽,通常具有强壮的翅膀和锐利的爪子,擅长在高空翱翔和捕猎。图片中的鹰展翅高飞,背景是蓝天白云,显得非常壮观。

上面是python请求案例

2. 先决条件

在继续此项目之前,请确保检查以下先决条件。

我们将使用 Arduino IDE 对 XIAO ESP32ESP32S3 Sense 开发板进行编程,因此在继续本教程之前,请确保已在 Arduino IDE 中安装这些开发板。

2.1 环境配置

  1. Arduino IDE:下载并安装 Arduino IDE;
  2. ESP32 开发板库:在 Arduino IDE 中添加 ESP32 支持;
    参考博客:【esp32c3配置arduino IDE教程】
    为安装过程留出一些时间,具体时间可能因您的互联网连接而异。

2.2 所需零件

要学习本教程,您需要1个XIAO ESP32ESP32S3 Sense,esp32s3搭配摄像头一起使用。

目前这是我使用的ESP32S3官方硬件👍👍👍(小小的身材有大大的力量)加摄像头麦克风79元,后期我会整理相关专栏进行Arduino系统学习😘😘😘。有需要可以购买xiao开发板💕💕💕,SeeedXIAO ESP32S3 Sense硬件购买地址:https://s.click.taobao.com/lekazrt

我们使用的是OV2640摄像头模块,它能够输出高质量的照片。请注意,不同的摄像头模块可能需要不同的引脚配置。

3. 核心代码

3.1 源码分享

esp32S3 Cam Arduino代码如下

cpp 复制代码
#include <Arduino.h>

#include "esp_camera.h"
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include <base64.h>
// #include "MY_WIFI.h"
#include <ArduinoJson.h>
#include "cJSON.h"
#include <HTTPClient.h>
#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 10
#define SIOD_GPIO_NUM 40
#define SIOC_GPIO_NUM 39

#define Y9_GPIO_NUM 48
#define Y8_GPIO_NUM 11
#define Y7_GPIO_NUM 12
#define Y6_GPIO_NUM 14
#define Y5_GPIO_NUM 16
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 17
#define Y2_GPIO_NUM 15
#define VSYNC_GPIO_NUM 38
#define HREF_GPIO_NUM 47
#define PCLK_GPIO_NUM 13

#define LED_GPIO_NUM 21

// 1. Replace with your network credentials
const char* ssid = "J09 502";
const char* password = "qwertyuiop111";
unsigned long lastCaptureTime = 0; // Last shooting time
int imageCount = 1;                // File Counter
bool camera_sign = false;          // Check camera status
bool sd_sign = false;              // Check sd status

// 2. Replace with your Ali API key
const char *apiKey = "sk-76a347d34b8d435982b1695";

// Send request to OpenAI API
String inputText = "你好,通义千问!";
String apiUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
char *data_json;
#define bufferLen 50000
String image_base64()
{
  // Take a photo
  camera_fb_t *fb = esp_camera_fb_get();
  if (!fb)
  {
    Serial.println("Failed to get camera frame buffer");
    return "error";
  }
  else
  {
    // fb->buf转为base64字符串
    String image = base64::encode(fb->buf, fb->len);
    Serial.println("image_base64 success");
    // Release image buffer
    esp_camera_fb_return(fb);
    return image;
  }
}

String image_request(String change) // 发送请求,返回的是请求结果代码,该码要填入下一个函数中(change是图片数据(jpg)
{
  memset(data_json, '\0', sizeof(data_json)); // 清空数组
  change.replace("\r\n", "");                 // 移除换行符

  strcat(data_json, "{\"model\":\"qwen-vl-plus\",\"messages\":[{\"role\":\"user\",\"content\":[");
  strcat(data_json, "{\"type\":\"image_url\",\"image_url\":{\"url\":\"data:image/jpeg;base64,");
  strcat(data_json, change.c_str()); // 添加base64编码数据
  strcat(data_json, "\"}},");
  strcat(data_json, "{\"type\":\"text\",\"text\":\"这是什么\"}]}]}");
  // Serial.println(data_json);
  // delay(2000);
  HTTPClient http_image_request;
  http_image_request.setTimeout(20000);
  http_image_request.begin(apiUrl);
  http_image_request.addHeader("Content-Type", "application/json");
  http_image_request.addHeader("Authorization", String("Bearer ") + String(apiKey));

  int httpCode = http_image_request.POST(data_json);
  if (httpCode == 200)
  {

    String response = http_image_request.getString();
    http_image_request.end();
    DynamicJsonDocument jsonDoc(1024);
    deserializeJson(jsonDoc, response);
    Serial.println(response);
    String id = jsonDoc["choices"][0]["message"]["content"];
    return id;
  }
  else
  {
    Serial.println("error request" + String(httpCode));
    http_image_request.end();
    return "error";
  }
}

void setup()
{
  Serial.begin(115200);
  while (!Serial)
    ; // When the serial monitor is turned on, the program starts to execute
  // Connect to Wi-Fi network
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
  data_json = (char *)ps_malloc(bufferLen * sizeof(char)); // 根据需要调整大小
  if (!data_json)
  {
    Serial.println("Failed to allocate memory for data_json");
  }
  Serial.println("Starting Camera");

  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.frame_size = FRAMESIZE_UXGA;
  config.pixel_format = PIXFORMAT_JPEG; // for streaming
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 12;
  config.fb_count = 1;

  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if (config.pixel_format == PIXFORMAT_JPEG)
  {
    if (psramFound())
    {
      config.jpeg_quality = 10;
      config.fb_count = 2;
      // config.grab_mode = CAMERA_GRAB_LATEST;
    }
    else
    {
      // Limit the frame size when PSRAM is not available
      config.frame_size = FRAMESIZE_SVGA;
      config.fb_location = CAMERA_FB_IN_DRAM;
    }
  }
  else
  {
    // Best option for face detection/recognition
    config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
    config.fb_count = 2;
#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;
  }
  Serial.println("Camera Ready");

  camera_sign = true; // Camera initialization check passes
}

void loop()
{
  // Camera & SD available, start taking pictures
  if (camera_sign)
  {
    // Get the current time
    unsigned long now = millis();

    // If it has been more than 1 minute since the last shot, take a picture and save it to the SD card
    if ((now - lastCaptureTime) >= 15000)
    {
      String image = image_base64();
      if (image != "error")
      {
        // Save the image to the SD card
        String image_answer = image_request(image);
        if (image_answer != "error")
        {
          Serial.println("Image sent to OpenAI API, answer: " + image_answer);
        }
      }
      lastCaptureTime = now;
    }
  }
}

首先将使用ESP32的摄像头模块拍摄照片,并通过阿里云提供的API接口发送图像数据,最后接收并解析API返回的结果。

3.2 源码解析

以下是详细的解释:

  1. 导入必要的库:
c 复制代码
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
  1. 第一处修改定义Wi-Fi网络凭证:
c 复制代码
// 1. Replace with your network credentials
const char* ssid = "J09 502";
const char* password = "qwertyuiop111";

注意:这里的WiFi尽量不要使用校园网,非常可能请求失败,建议换成自己的热点啥的宽度。😁😁😁

  1. 第二处修改定义要调用的APIkey:
c 复制代码
// 2. Replace with your Ali API key
const char *apiKey = "sk-76a347d34b8d435982b1695";

4. 上传验证

下面给出下载配置,请严格配置

4.1 下载配置

如果提示Compilation error: ArduinoJson.h: No such file or directory

直接在库管理安装Arduinojson

4.2 打开串口

摄像头每10秒获取一张照片,然后调用阿里云图像大模型进行交互,我前前后后测试了,大约40次请求,会出现4次重启,然后20次调用成功,16次调用失败,可能获取数据没有优化好,存在请求参数不合法以及网路延迟效果。

5. 总结

🥳🥳🥳现在,我们在本教程中,成功地使用ESP32开发板接入了阿里云的大模型服务,实现了图像的理解功能。这个项目不仅展示了ESP32的强大功能,还为我们提供了一个实践深度学习和机器视觉的机会。希望本文能够帮助你在物联网和人工智能领域迈出坚实的一步。🛹🛹🛹从而实现对外部世界进行感知,充分认识这个有机与无机的环境,后期会持续分享esp32跑freertos实用案列🥳🥳🥳科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣

如果你有任何问题,可以通过q group(945348278)加入鹏鹏小分队,期待与你思维的碰撞😘😘😘

相关推荐
dessler1 小时前
Linux系统-开关机
linux·运维·云计算
大数据AI人工智能培训专家培训讲师叶梓9 小时前
基于模型内部的检索增强型生成答案归属方法:MIRAGE
人工智能·自然语言处理·性能优化·大模型·微调·调优·检索增强型生成
中杯可乐多加冰10 小时前
【AI应用落地实战】智能文档处理本地部署——可视化文档解析前端TextIn ParseX实践
人工智能·深度学习·大模型·ocr·智能文档处理·acge·textin
bala556914 小时前
Docker-在Centos中部署Shell脚本获取镜像并构建容器
linux·阿里云·docker·容器·centos·maven
~见贤思齐~18 小时前
记一次真实项目的性能问题诊断、优化(阿里云redis分片带宽限制问题)过程
redis·阿里云·云计算·1024程序员节
瑕、疵1 天前
云计算平台上的DevOps实践
运维·云计算·devops
李李李李李同学1 天前
云计算过二级等保的要求,应该怎么做?
网络·安全·云计算·等保测评
百度智能云技术站1 天前
AI 原生时代,更要上云:百度智能云云原生创新实践
云原生·大模型·智能化·ai 原生
木子Linux1 天前
【云计算】KVM虚拟化部署
linux·运维·服务器·云计算
小安运维日记1 天前
Linux云计算 |【第五阶段】CLOUD-DAY4
linux·运维·docker·云计算·改行学it