Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
AI_人工智能
ART-Pi
基于 ART-Pi 实现的百度 AI 图像识别
发布于 2021-03-22 09:15:00 浏览:20617
订阅该版
[tocm] # 基于 ART-Pi 实现的 AI 图像识别 不用自己训练模型,也能进行 AI 图像识别;借助百度云平台,我们可以在 APT-Pi 上实现图像识别功能。 ## 创建图像识别应用 1. 打开链接 [百度智能云](https://cloud.baidu.com/), 申请账号; 2. 打开控制台  3. 打开图像识别  4. 创建应用  5. 获取 AK 和 SK  ## 通用图像识别 该请求用于通用物体及场景识别,即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片中的多个物体及场景标签。 1. 打开 image_classify.c 文件, 修改 `access_token`, 填入应用的 AK 和 SK;  2. 在 SD 卡中放入要识别的图片; 3. 编译下载; 4. 在终端输入命令: `baidu_ai cat.jpg`  5. 加入百度百科,使能宏定义:`#define BD_AI_BAIKE`,编译下载:  ### 返回说明 **返回参数** | 字段 | 是否必选 | 类型 | 说明 | | ------------- | -------- | ------------- | --------------------------------------------------------- | | log_id | 是 | uint64 | 唯一的log id,用于问题定位 | | result_num | 是 | unit32 | 返回结果数目,及result数组中的元素个数 | | result | 是 | arrry(object) | 标签结果数组 | | +keyword | 是 | string | 图片中的物体或场景名称 | | +score | 是 | float | 置信度,0-1 | | +root | 是 | string | 识别结果的上层标签,有部分钱币、动漫、烟酒等tag无上层标签 | | +baike_info | 否 | object | 对应识别结果的百科词条名称 | | ++baike_url | 否 | string | 对应识别结果百度百科页面链接 | | ++image_url | 否 | string | 对应识别结果百科图片链接 | | ++description | 否 | string | 对应识别结果百科内容描述 | ## 菜品识别 该请求用于菜品识别。即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片的菜品名称、卡路里信息、置信度。 1. 修改 URL 为菜品识别: ```c index = strlen(BAIDU_AI_API[1]); post_uri_size = index; post_uri = rt_malloc(256); rt_memcpy(post_uri, BAIDU_AI_API[1], post_uri_size); ``` 2. 编译下载; 3. 识别结果:  ### 返回说明 **返回参数** | 字段 | 是否必选 | 类型 | 说明 | | ------------- | -------- | ------- | -------------------------------------- | | log_id | 是 | uint64 | 唯一的log id,用于问题定位 | | result_num | 否 | unit32 | 返回结果数目,及result数组中的元素个数 | | result | 否 | array() | 菜品识别结果数组 | | +name | 否 | string | 菜名,示例:鱼香肉丝 | | +calorie | 否 | float | 卡路里,每100g的卡路里含量 | | +probability | 否 | float | 识别结果中每一行的置信度值,0-1 | | +baike_info | 否 | object | 对应识别结果的百科词条名称 | | ++baike_url | 否 | string | 对应识别结果百度百科页面链接 | | ++image_url | 否 | string | 对应识别结果百科图片链接 | | ++description | 否 | string | 对应识别结果百科内容描述 | ## 监控报表 在百度服务端,可以查看 API 调用成功和失败的次数:  ## 图像格式 图像格式转换流程:  1. 百度 AI 支持的图像格式有:PNG、JPG、JPEG、BMP 2. 原始的图片数据需要转换为 base64 编码 3. base64 编码的图片数据进行百分比编码 ### Base64 编码 请求图片需经过`base64编码`:图片的base64编码指将一副图片数据编码成一串字符串,使用该字符串代替图像地址。您可以首先得到图片的二进制,然后用Base64格式编码即可。 Base64是网络上最常见的用于传输8Bit[字节码](https://baike.baidu.com/item/字节码/9953683)的编码方式之一,Base64就是一种基于64个可打印字符来表示[二进制](https://baike.baidu.com/item/二进制/361457)数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。 Base64编码是从二进制到字符的过程,可用于在[HTTP](https://baike.baidu.com/item/HTTP)环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。 Base64由于以上优点被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上“符号类”字符(+, /, =),不同的应用场景又分别研制了Base64的各种“变种”。为统一和规范化Base64的输出,Base62x被视为无符号化的改进版本。 ### 百分比编码 百分比编码 是一种拥有8位字符编码的编码机制,这些编码在URL的上下文中具有特定的含义。它有时被称为URL编码。编码由英文字母替换组成:“%” 后跟替换字符的ASCII的十六进制表示。 需要编码的特殊字符有:`':','/','?','#','[',']','@','!','$','&',"'",'(',')','*','+',',',';','=',以及,'%'`` 本身.` 其他的字符虽然可以进行编码但是不需要。 `':' '/' '?' '#' '[' ']' '@' '!' '$' '&' "'" '(' ')' '*' '+' ',' ';' '=' '%' ' '` `%3A %2F %3F %23 %5B %5D %40 %21 %24 %26 %27 %28 %29 %2A %2B %2C %3B %3D %25 %20 或 +` 根据上下文, 空白符 ’ ’ 将会转换为 ‘+’ (必须在HTTP的POST方法中使定义 application/x-www-form-urlencoded 传输方式), 或者将会转换为 ‘%20’ 的 URL。 ## 图像识别流程 ### **获取 token** ```c /* get token */ int get_ai_token(const char *uri, unsigned char *token) { char *request = RT_NULL; int token_len = 0, index = 0; cJSON* cjson_parse = RT_NULL; cJSON* cjson_token = RT_NULL; if (webclient_request(uri, RT_NULL, RT_NULL, (unsigned char **)&request) < 0) { rt_kprintf("webclient send get request failed."); return -RT_ERROR; } rt_kprintf("webclient send get request by simplify request interface.\n"); rt_kprintf("webclient get response data: \n"); for (index = 0; index < rt_strlen(request); index++) { rt_kprintf("%c", request[index]); } rt_kprintf("\n"); cjson_parse = cJSON_Parse(request); if(cjson_parse == RT_NULL) { LOG_E("parse fail.\n"); goto __exit; } cjson_token = cJSON_GetObjectItem(cjson_parse, "access_token"); if (cjson_token == RT_NULL) { LOG_E("get onject 'access_token' item fail.\n"); goto __exit; } LOG_D("get_token: %s\n", cjson_token->valuestring); token_len = rt_strlen(cjson_token->valuestring); rt_memcpy(token, cjson_token->valuestring, token_len); __exit: if (cjson_parse) { cJSON_Delete(cjson_parse); cjson_parse = RT_NULL; cjson_token = RT_NULL; } if (request) { web_free(request); } return token_len; } ``` ### 图片数据编码 #### Base 64 ```c static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* encode image */ int base64_encode(unsigned char * bytes_to_encode, unsigned char *encode, int bytes_len) { int i = 0, j = 0, encode_size = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (bytes_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; i < 4; i++) { encode[encode_size++] = base64_chars[char_array_4[i]]; } i = 0; } } if (i) { for (j = i; j < 3; j++) { char_array_3[j] = '\0'; } char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(j = 0; (j < i + 1); j++) { encode[encode_size++] = base64_chars[char_array_4[j]]; } while ((i++ < 3)) { encode[encode_size++] = '='; } } return encode_size; } ``` #### 百分比编码 ```c int http_percentage_coding(unsigned char *org_data, unsigned char *new_data, int len) { int i = 0; unsigned char org_char = 0; while (len--) { org_char = *(org_data++); switch (org_char) { case ':' : new_data[i++] = '%'; new_data[i++] = '3'; new_data[i++] = 'A'; break; case '/' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = 'F'; break; case '?' : new_data[i++] = '%'; new_data[i++] = '3'; new_data[i++] = 'F'; break; case '#' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '3'; break; case '[' : new_data[i++] = '%'; new_data[i++] = '5'; new_data[i++] = 'B'; break; case ']' : new_data[i++] = '%'; new_data[i++] = '5'; new_data[i++] = 'D'; break; case '@' : new_data[i++] = '%'; new_data[i++] = '4'; new_data[i++] = '0'; break; case '!' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '1'; break; case '$' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '4'; break; case '&' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '6'; break; case '\'' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '7'; break; case '(' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '8'; break; case ')' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '9'; break; case '*' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = 'A'; break; case '+' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = 'B'; break; case ',' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = 'C'; break; case ';' : new_data[i++] = '%'; new_data[i++] = '3'; new_data[i++] = 'B'; break; case '=' : new_data[i++] = '%'; new_data[i++] = '3'; new_data[i++] = 'D'; break; case '%' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '5'; break; case ' ' : new_data[i++] = '%'; new_data[i++] = '2'; new_data[i++] = '0'; break; default: new_data[i++] = org_char; break; } } return i; } ``` ### 获取识别结果 ```c int get_ai_result(const char *uri, const char *post_data, int post_data_size) { struct webclient_session* session = RT_NULL; unsigned char *buffer = RT_NULL; int index, result = 0, resp_status, bytes_read; buffer = (unsigned char *)web_malloc(POST_RESP_BUFSZ); if (buffer == RT_NULL) { rt_kprintf("no memory for receive response buffer.\n"); result = -RT_ENOMEM; goto __exit; } /* create webclient session and set header response size */ session = webclient_session_create(POST_HEADER_BUFSZ); if (session == RT_NULL) { result = -RT_ENOMEM; goto __exit; } /* add http header */ webclient_header_fields_add(session, "Content-Length: %d\r\n", post_data_size); webclient_header_fields_add(session, "Content-Type: application/x-www-form-urlencoded\r\n"); /* send POST request by default header */ if ((resp_status = webclient_post(session, uri, (const char *)post_data)) != 200) { LOG_E("webclient POST request failed, response(%d) error.\n", resp_status); result = -RT_ERROR; goto __exit; } rt_kprintf("webclient post response data: \n"); do { bytes_read = webclient_read(session, buffer, POST_RESP_BUFSZ); if (bytes_read <= 0) { break; } for (index = 0; index < bytes_read; index++) { rt_kprintf("%c", buffer[index]); } } while (1); rt_kprintf("\n"); __exit: if (session) { webclient_close(session); } if (buffer) { web_free(buffer); } return result; } ``` ## 仓库地址 [基于 ART-PI 实现的百度 AI 图片识别 (github.com)](https://github.com/thread-liu/ART-PI_BAIDUAI)
8
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
Papalymo
请勿打扰
文章
25
回答
85
被采纳
17
关注TA
发私信
相关文章
1
RT-Thread Studio 编译ART-Pi 的SDK报错 求助!-
2
ART-Pi 在 Studio 中使用TouchGFX Library 编译报错
3
RT-Thread Studio 更新错误
4
基于ART-Pi开发板创建的工程,RT-Thread Settings打不开
5
在 ART-Pi 平台使用 openocd 直接烧录到外部 spi flash?
6
ART-Pi工程用mdk5打开后提示文件找不到
7
ART-PI demo是否能够增加demo流程框图或者详细设计文档
8
ART-Pi 的ST_Link无法识别
9
请把ART-Pi仓库放到gitee上一份。
10
仅有ART-Pi开发包时,RTT Studio无法创建ART-Pi工程
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
GD32
ADC
flashDB
编译报错
socket
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
出出啊
1520
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
550
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
5
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
1
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部