电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
在RT-Thread的ART-PI平台,进行图片识别
分 享
扫描二维码分享
在RT-Thread的ART-PI平台,进行图片识别
APT-PI
图像识别
RTThread
Rice嵌入式开发
关注
发布时间: 2021-03-08
丨
阅读: 701
## 摘要 - 最近在完成2020年没有完成的一个DIY项目,去年年底整个人有点泄气,导致一直搁置的。现在重新把他做好 - 因为项目DIY项目中想引入图片识别,但是我的DIY作品不方便使用烧录等,所以我想用ART-PI来进行调试测试。 - 这个功能取决于强大的RT-THREAD软件包,只需要勾勾选选,就可以实现了。 ## 图片识别实现 #### 开发环境: - 平台:rt-thread的ART-PI。 - 软件包:webclient-v2.1.2,cjson-v1.0.2,mbedtls-v2.7.10。 - 图片识别平台:百度云平台。 #### 百度云平台 - 我的这个图片识别,是依赖百度云平台提供的图片识别API。 - 步骤: 1. 需要注册一个百度云账号。 ![](https://RiceChen0.gitee.io/picture/baiduyun/1.png) 2. 然后选择人工智能->图片识别。 ![](https://RiceChen0.gitee.io/picture/baiduyun/2.png) 3. 百度云提供不同类别的API,而我这里选择了通用物体和场景识别 ![](https://RiceChen0.gitee.io/picture/baiduyun/3.png) 4. 点击技术文档 ![](https://RiceChen0.gitee.io/picture/baiduyun/4.png) 5. 技术文档中,百度云提供了通用物体和场景识别API的详细说明:①HTTP方法:post。②请求URL。③URL参数:token和header。④百度云提供了不同语言的开发实例。而我们使用的是基于RTT来开发,所以需要对其进行造轮子(可以根据bash的实例来了解)。 ![](https://RiceChen0.gitee.io/picture/baiduyun/5.png) 6. bash的例子: ``` C curl -i -k 'https://aip.baidubce.com/rest/2.0/image-classify/v2/advanced_general?access_token=【调用鉴权接口获取的token】' --data 'image=【图片Base64编码,需UrlEncode】' -H 'Content-Type:application/x-www-form-urlencoded' ``` - 注意:需要注意的是图片需要进行Base64编码和UrlEncode ![](https://RiceChen0.gitee.io/picture/baiduyun/10.png) #### rt-thread代码实现: - 增加软件:webclient-v2.1.2,cjson-v1.0.2,mbedtls-v2.7.10 - 通过HTTP方法:get获取token。 1. token的获取方法可以看百度云的教程,如下: ![](https://RiceChen0.gitee.io/picture/baiduyun/9.png) 2. 需要AK(API Key)和SK(Secret Key) ```C curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】' ``` 3. AK和SK获取方式,需要通过创建一个应用,以个人的方式创建。 ![](https://RiceChen0.gitee.io/picture/baiduyun/6.png) ![](https://RiceChen0.gitee.io/picture/baiduyun/7.png) ![](https://RiceChen0.gitee.io/picture/baiduyun/8.png) 4. rt-thread代码实现获取token ```C #define GET_TOKEN_URI "http://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=[填入自己的AK]&client_secret=[填入自己SK]" void rp_get_token(void) { char *response = RT_NULL; char *uri = RT_NULL; uri = web_strdup(GET_TOKEN_URI); if (webclient_request(uri, RT_NULL, RT_NULL, (unsigned char **)&response) < 0) { rt_kprintf("get image fail!\n"); return -RT_ERROR; } image_info->root = cJSON_Parse(response); if(image_info->root != RT_NULL) { image_info->token = cJSON_GetObjectItem(image_info->root, "access_token"); rt_kprintf("token : %s\n", image_info->token->valuestring); } } ``` 5. Base64编码函数: ``` C const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *base64_encode(char *bindata, char *base64, int binlength) { int i, j; unsigned char current; for ( i = 0, j = 0 ; i < binlength ; i += 3 ) { current = (bindata[i] >> 2) ; current &= (unsigned char)0x3F; base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ; if ( i + 1 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; base64[j++] = '='; break; } current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ; if ( i + 2 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; break; } current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ; base64[j++] = base64char[(int)current]; } base64[j] = '\0'; return 0; } ``` 6. 图片UrlEncode: ```C static rt_bool_t is_non_symbol(char c) { if(c == '\0') return 1; int c_int = (int)c; return (c_int >= 48 && c_int <= 57) || (c_int >= 65 && c_int <= 90) || (c_int >= 97 && c_int <= 122); } char *url_encode(const char *input) { int end = strlen(input); size_t final_size = (end * 3) + 1; char *working = rt_malloc(final_size); char *output = working; if(working == NULL) { rt_kprintf("working malloc failed\n"); } while(*input) { const char c = *input; if(c < 0) { input++; } else if(is_non_symbol(c)) { *working++ = *input++; } else { char encoded[4] = {0}; snprintf(encoded, 4, "%%%02X", c); *working++ = encoded[0]; *working++ = encoded[1]; *working++ = encoded[2]; input++; } } *working = 0; //psram_free(working); return output; } ``` 7. rt-thread实现图片识别结果请求 ```C void rp_get_image_result(void) { rt_uint8_t *image_tag = "image="; // 获取图片编码后的数据 rt_uint8_t *image_base64 = pic_base64("./flash/fish.jpg"); rt_uint32_t image_tag_len = 0; rt_uint32_t image_base64_len = 0; rt_uint8_t *params = RT_NULL; image_tag_len = strlen(image_tag); image_base64_len = strlen(image_base64); params = rt_malloc(image_tag_len + image_base64_len); // 拼接HTTP请求格式中的(--data) 的数据 rt_memcpy(params, image_tag, image_tag_len); rt_memcpy(params + image_tag_len, image_base64, image_base64_len); char *image_uri = RT_NULL; char *header = RT_NULL; char *image_result = RT_NULL; int index = 0; image_uri = web_strdup(GET_IMAGE_RESULT_URI); // HTTP header数据 webclient_request_header_add(&header, "Content-Length: %d\r\n", image_tag_len + image_base64_len); webclient_request_header_add(&header, "Content-Type: application/x-www-form-urlencoded\r\n"); // HTTP POST if (webclient_request(image_uri, (const char *)header, params, (unsigned char **)&image_result) < 0) { rt_kprintf("webclient send post request failed."); web_free(header); return -RT_ERROR; } // 答应返回结果 for (index = 0; index < rt_strlen(image_result); index++) { rt_kprintf("%c", image_result[index]); } rt_kprintf("\n"); } ``` 8. 测试图片: ![](https://RiceChen0.gitee.io/picture/baiduyun/fish.jpg) 9. 测试结果: ![](https://RiceChen0.gitee.io/picture/baiduyun/11.png)
关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。 ![](https://RiceChen0.gitee.io/picture/logo/logo_.jpg)
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
Rice嵌入式开发
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交