[ESP32]:基于HTTP实现百度AI识图
测试环境:
- esp32-s3
- esp idf 5.1
首先,先配置sdk,可以写入到sdkconfig.defaults
CONFIG_IDF_TARGET="esp32s3"
CONFIG_IDF_TARGET_ESP32S3=yCONFIG_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 sizefor (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 sizeif (dlen < j + 1){*olen = j + 1; // reytun need sizereturn -1;}// url encodefor (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 enddst[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 sizefor (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 sizeif (dlen < j + 1){*olen = j + 1; // reytun need sizereturn -1;}// url encodefor (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 enddst[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 encodembedtls_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 encodeurl_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 paramsimg_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 settingchar 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.实验效果
拿了一张泰勒的图来识别