[ESP32]:基于HTTP实现百度AI识图

[ESP32]:基于HTTP实现百度AI识图

测试环境:

  • esp32-s3
  • esp idf 5.1

首先,先配置sdk,可以写入到sdkconfig.defaults

CONFIG_IDF_TARGET="esp32s3"
CONFIG_IDF_TARGET_ESP32S3=y

CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

CONFIG_ESP_TLS_INSECURE=y
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y

这里关闭了认证,并且建了分区表来存放我们待识别的图片。

1.百度控制台调试

1.获取token

在这里插入图片描述

2.在线调试,看下传输过程

在这里插入图片描述

主要关注如下内容:

header:

{
    "Accept": "application/json",
    "Content-Type": "application/x-www-form-urlencoded"
}

body:

image=%2F9j%2F4AAQSkZJRgABAQEBLAEsAAD%2F2wBDAAUEBAUEAwUFBAUGBgUGCA4JCAcHCBEMDQoO...

其中imge图像要先base64编码,在url编码

2.esp32调试

我们这里主要参考esp http client的代码

1.base64编码

esp-idf中已经有base64编码的代码,我们include一下即可

#include "mbedtls/base64.h"

int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
                          const unsigned char *src, size_t slen)
2.url编码

这个要自己实现一下

int url_encode(const unsigned char *src, size_t slen, size_t *olen, unsigned char *dst, size_t dlen)
{
    size_t i, j = 0;

    // clac encoed size
    for (i = 0; i < slen; i++)
    {
        if ((src[i] >= 'A' && src[i] <= 'Z') ||
            (src[i] >= 'a' && src[i] <= 'z') ||
            (src[i] >= '0' && src[i] <= '9') ||
            src[i] == '-' || src[i] == '_' || src[i] == '.' || src[i] == '~')
        {
            j++;
        }
        else if (src[i] == ' ')
        {
            j++;
        }
        else
        {
            j += 3; // length of %xx is three
        }
    }

    // check buffer size
    if (dlen < j + 1)
    {
        *olen = j + 1; // reytun need size
        return -1;
    }

    // url encode
    for (i = 0, j = 0; i < slen; i++)
    {
        if ((src[i] >= 'A' && src[i] <= 'Z') ||
            (src[i] >= 'a' && src[i] <= 'z') ||
            (src[i] >= '0' && src[i] <= '9') ||
            src[i] == '-' || src[i] == '_' || src[i] == '.' || src[i] == '~')
        {
            dst[j++] = src[i];
        }
        else if (src[i] == ' ')
        {
            dst[j++] = '+';
        }
        else
        {
            dst[j++] = '%';
            dst[j++] = "0123456789ABCDEF"[src[i] >> 4];
            dst[j++] = "0123456789ABCDEF"[src[i] & 0x0F];
        }
    }

    // add end
    dst[j] = '\0';

    // return size
    *olen = j;

    return 0;
}
3.添加http client的调用
 char post_url[1024] = {0};
    esp_http_client_config_t config = {
        .method = HTTP_METHOD_POST,
        .event_handler = app_http_baidu_event_handler,
        .buffer_size = 4 * 1024,
    };
    sprintf(post_url, "%s?access_token=%s", base_url, access_token);
    config.url = post_url;
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_post_field(client, img_params, strlen(img_params)); //填入url编码后的图像数据
    esp_http_client_set_header(client, "Content-Type", "application/x-www-form-urlencoded");
    esp_err_t err = esp_http_client_perform(client);
    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d", esp_http_client_get_status_code(client), (int)esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGI(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);
4.整体代码
#include "app_baidu.h"
#include "mbedtls/base64.h"
#include "esp_http_client.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "string.h"

static const char *TAG = "HTTP_BAIDU";

char access_token[256] = "xxxx"; //更换自己的token
char base_url[256] = "https://aip.baidubce.com/rest/2.0/image-classify/v2/advanced_general";

esp_err_t app_http_baidu_event_handler(esp_http_client_event_t *evt)
{
    if (evt->event_id == HTTP_EVENT_ON_DATA)
    {
        ESP_LOGI(TAG, "%s",(char *)evt->data);
    }

    return ESP_OK;
}

int url_encode(const unsigned char *src, size_t slen, size_t *olen, unsigned char *dst, size_t dlen)
{
    size_t i, j = 0;

    // clac encoed size
    for (i = 0; i < slen; i++)
    {
        if ((src[i] >= 'A' && src[i] <= 'Z') ||
            (src[i] >= 'a' && src[i] <= 'z') ||
            (src[i] >= '0' && src[i] <= '9') ||
            src[i] == '-' || src[i] == '_' || src[i] == '.' || src[i] == '~')
        {
            j++;
        }
        else if (src[i] == ' ')
        {
            j++;
        }
        else
        {
            j += 3; // length of %xx is three
        }
    }

    // check buffer size
    if (dlen < j + 1)
    {
        *olen = j + 1; // reytun need size
        return -1;
    }

    // url encode
    for (i = 0, j = 0; i < slen; i++)
    {
        if ((src[i] >= 'A' && src[i] <= 'Z') ||
            (src[i] >= 'a' && src[i] <= 'z') ||
            (src[i] >= '0' && src[i] <= '9') ||
            src[i] == '-' || src[i] == '_' || src[i] == '.' || src[i] == '~')
        {
            dst[j++] = src[i];
        }
        else if (src[i] == ' ')
        {
            dst[j++] = '+';
        }
        else
        {
            dst[j++] = '%';
            dst[j++] = "0123456789ABCDEF"[src[i] >> 4];
            dst[j++] = "0123456789ABCDEF"[src[i] & 0x0F];
        }
    }

    // add end
    dst[j] = '\0';

    // return size
    *olen = j;

    return 0;
}

// base64 encode: http://www.yzcopen.com/img/imgbase64
// url encode: https://www.jyshare.com/front-end/695/?
void app_baidu_classification(char *img_buf, int file_size)
{
    char *img_base64 = NULL;
    char *img_params = NULL;
    char *img_base64_url = NULL;
    char *img_params_format = "image=%s";
    size_t img_base64_size = 0;
    size_t img_base64_url_size = 0;

    // base64 encode
    mbedtls_base64_encode(NULL, 0, &img_base64_size, (const unsigned char *)img_buf, file_size);
    ESP_LOGI(TAG, "Image size after bash64:%zu", img_base64_size);

    img_base64 = heap_caps_calloc(1, img_base64_size + 1, MALLOC_CAP_DMA);
    if (img_base64 == NULL)
    {
        ESP_LOGI(TAG, "Memory image bash64 allocation failed");
        return;
    }
    mbedtls_base64_encode((unsigned char *)img_base64, img_base64_size + 1, &img_base64_size, (const unsigned char *)img_buf, file_size);

    // url encode
    url_encode((const unsigned char *)img_base64, img_base64_size, &img_base64_url_size, NULL, 0);
    ESP_LOGI(TAG, "Image size after url:%zu", img_base64_url_size);

    img_base64_url = heap_caps_calloc(1, img_base64_url_size + 1, MALLOC_CAP_DMA);
    if (img_base64_url == NULL)
    {
        ESP_LOGI(TAG, "Memory image bash64 url allocation failed");
        free(img_base64);
        return;
    }
    url_encode((const unsigned char *)img_base64, img_base64_size, &img_base64_url_size, (unsigned char *)img_base64_url, img_base64_url_size + 1);

    // set data params
    img_params = heap_caps_calloc(1, img_base64_url_size + 1 + strlen(img_params_format), MALLOC_CAP_DMA);
    if (img_params == NULL)
    {
        ESP_LOGI(TAG, "Memory image params allocation failed");
        free(img_base64);
        free(img_base64_url);
        return;
    }

    sprintf(img_params, img_params_format, img_base64_url);

    // http client setting

    char post_url[1024] = {0};
    esp_http_client_config_t config = {
        .method = HTTP_METHOD_POST,
        .event_handler = app_http_baidu_event_handler,
        .buffer_size = 4 * 1024,
    };
    sprintf(post_url, "%s?access_token=%s", base_url, access_token);
    config.url = post_url;
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_post_field(client, img_params, strlen(img_params));
    esp_http_client_set_header(client, "Content-Type", "application/x-www-form-urlencoded");
    esp_err_t err = esp_http_client_perform(client);
    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d", esp_http_client_get_status_code(client), (int)esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGI(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
    }
    esp_http_client_cleanup(client);

    free(img_base64);
    free(img_base64_url);
    free(img_params);
}

3.实验效果

拿了一张泰勒的图来识别

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/470338.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springcloud修炼——Eureka注册中心

如果你要理解这个技术博客博客专栏 请先学习以下基本的知识&#xff1a; 什么是微服务什么是服务拆分什么是springcloud Springcloud为微服务开发提供了一个比较泛用和全面的解决框架&#xff0c;springcloud继承了spring一直以来的风格——不重复造轮子&#xff0c;里面很多的…

四、C#希尔排序算法

简介 希尔排序简单的来说就是一种改进的插入排序算法&#xff0c;它通过将待排序的元素分成若干个子序列&#xff0c;然后对每个子序列进行插入排序&#xff0c;最终逐步缩小子序列的间隔&#xff0c;直到整个序列变得有序。希尔排序的主要思想是通过插入排序的优势&#xff0…

python在线图书馆信息管理系统flask-django-nodejs-php

随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;在线图书信息管理系统也不例外&#xff0c;但目前国内的市场仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&…

[AIGC] 在Spring Boot中指定请求体格式

在使用Spring Boot开发Web应用的时候&#xff0c;我们经常会遇到需要接收并处理HTTP请求的情况。一个HTTP请求通常包括一个请求行、若干请求头和一个请求体。请求体在POST和PUT请求中特别重要&#xff0c;因为它通常用于向服务器传递数据。 文章目录 创建并使用一个Java Bean指…

【智能家居】东胜物联提供软硬一体化智能家居解决方案,助企业提高市场占有率

背景 随着智能家居市场的不断壮大&#xff0c;越来越多的消费者开始享受到它带来的便捷和效益。现在&#xff0c;他们可以通过远程或语音控制设备进行个性化设置&#xff0c;比如调节照明和温度&#xff0c;让生活变得更加舒适和智能化。 根据SPER市场研究&#xff0c;预计秘…

整蛊小教程|让朋友手足无措的电脑自动关机

前言 这几天讲到shutdown关机命令&#xff0c;于是就出现了整蛊类的电脑教程。 这个故事我记得很清楚&#xff1a;在2012年的春天……当时的小白对电脑还不是很熟悉。某一天跟着朋友去网吧上网&#xff0c;这时候突然有个朋友发来一个.bat的文件&#xff0c;说双击打开有惊喜…

多特征变量序列预测(11) 基于Pytorch的TCN-GRU预测模型

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较-CSDN博客 风速预测&#xff08;一&#xff09;数据集介绍和预处理-CSDN博客 风速预测&#xff08;二&#xff09;基于Pytorch的EMD-LSTM模型-CSDN博客 风速预测&#xff…

学习vue3第八节(自定义指令 directive)

1、自定义指令的作用&#xff1a; 自定义指令是用来操作底层DOM的&#xff0c;尽管vue推崇数据驱动视图的理念&#xff0c;但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和拓展&#xff0c;不仅仅可用于定义任何DOM操作&#xff0c;并且是可以重复使用。 自定义…

[蓝桥杯 2020 省 AB3] 限高杆

分层图建图典题 #include<bits/stdc.h> using namespace std; using ll long long; #define int long long const int N 6e510; const int inf 0x3f3f3f3f; const int mod 1e97; int e[N],ne[N],w[N],h[N],idx; void add(int a,int b,int c){e[idx] b,ne[idx] h[a]…

DOcker搭建Rancher

简介 Rancher 是供采用容器的团队使用的完整软件堆栈。它解决了管理多个Kubernetes集群的运营和安全挑战&#xff0c;并为DevOps团队提供用于运行容器化工作负载的集成工具。 官网地址&#xff1a;https://www.rancher.cn/ 安装 拉取镜像 docker pull rancher/rancher:stab…

Kotlin中单例模式和Java的对比浅析

前言 单例模式&#xff0c;一直以来是我们在日常开发中最常用的一种设计模式&#xff0c;更是面试中非常重要&#xff0c;也非常容易被问到的问题。在日常开发中&#xff0c;大家常用的语言还是Java&#xff0c;但今天我给大家带来的是在Kotlin语言中&#xff0c;单例模式是怎…

【视觉语言大模型+LLaVA1.0】大语言模型视觉助手(视觉指令调优)GPT4-Vision丐版

官方资源汇总&#xff1a; 项目主页 || https://huggingface.co/liuhaotian 23.04.LLaVA1.论文: Large Language and Vision Assistant&#xff08;Visual Instruction Tuning) 23.10 LLaVA-1.5论文: Improved Baselines with Visual Instruction Tuning 23.11 LLaVA-Plus项目&…

基于python+vue智慧社区家政服务系统的设计与实现flask-django-nodejs

论文主要是对智慧社区家政服务系统进行了介绍&#xff0c;包括研究的现状&#xff0c;还有涉及的开发背景&#xff0c;然后还对系统的设计目标进行了论述&#xff0c;还有系统的需求&#xff0c;以及整个的设计方案&#xff0c;对系统的设计以及实现&#xff0c;也都论述的比较…

【Thread 线程】线程的方法与状态

SueWakeup 个人中心&#xff1a;SueWakeup 系列专栏&#xff1a;学习Java 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f7; 友情赞助播出&#xff01; 目录 一个线程的生命周期 线程终止的原因 线程的方法 Thread 类的静态方法 1. 设置线程…

六、C#快速排序算法

简介 快速排序是一种常用的排序算法&#xff0c;它基于分治的思想&#xff0c;通过将一个无序的序列分割成两个子序列&#xff0c;并递归地对子序列进行排序&#xff0c;最终完成整个序列的排序。 其基本思路如下&#xff1a; 选择数组中的一个元素作为基准&#xff08;pivot…

第四百一十二回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题的结果"相关的内容&#xff0c;本章回中将介绍自定义标题栏.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我…

KKVIEW远程控制 手机远程控制电脑

机远程控制电脑&#xff1a;实现跨设备便捷操作 随着科技的飞速发展&#xff0c;智能手机和电脑已成为我们日常生活中不可或缺的工具。有时&#xff0c;我们可能需要在不直接接触电脑的情况下对其进行操作&#xff0c;这时&#xff0c;手机远程控制电脑的技术就显得尤为重要。…

深入理解栈和队列(一):栈

个人主页&#xff1a;17_Kevin-CSDN博客 专栏&#xff1a;《数据结构》 一、栈的概念 栈&#xff08;Stack&#xff09;是一种特殊的线性表&#xff0c;它遵循后进先出&#xff08;Last-In-First-Out&#xff0c;LIFO&#xff09;的原则。栈可以被看作是一个只能在一端进行操作…

内网横向移动小结

windows Windows-Mimikatz 适用环境&#xff1a; 微软为了防止明文密码泄露发布了补丁 KB2871997&#xff0c;关闭了 Wdigest 功能。当系统为 win10 或 2012R2 以上时&#xff0c;默认在内存缓存中禁止保存明文密码&#xff0c;此时可以通过修改注册表的方式抓取明文&#xff…

selenium 元素定位攻略大全

一、By类单一属性定位 元素名称描述Webdriver APIidid属性driver.find_element(By.ID, "id属性值")namename属性driver.find_element(By.NAME, "name属性值")class_nameclass属性driver.find_element(By.CLASS_NAME, "class_name属性值")tag_na…