Rice我叫加饭? · 2021年03月08日

在RT-Thread的ART-PI平台,进行图片识别

摘要

  • 最近在完成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. 需要注册一个百度云账号。

image.png

  1. 然后选择人工智能->图片识别。

image.png

  1. 百度云提供不同类别的API,而我这里选择了通用物体和场景识别

image.png

  1. 点击技术文档

image.png

  1. 技术文档中,百度云提供了通用物体和场景识别API的详细说明:①HTTP方法:post。②请求URL。③URL参数:token和header。④百度云提供了不同语言的开发实例。而我们使用的是基于RTT来开发,所以需要对其进行造轮子(可以根据bash的实例来了解)。

image.png

  1. bash的例子:

`curl -i -k 'https://aip.baidubce.com/rest...【调用鉴权接口获取的token】' --data 'image=【图片Base64编码,需UrlEncode】' -H 'Content-Type:application/x-www-form-urlencoded'
`

  • 注意:需要注意的是图片需要进行Base64编码和UrlEncode

image.png

rt-thread代码实现:

  • 增加软件:webclient-v2.1.2,cjson-v1.0.2,mbedtls-v2.7.10
  • 通过HTTP方法:get获取token。
  1. token的获取方法可以看百度云的教程,如下:

image.png

  1. 需要AK(API Key)和SK(Secret Key)

`curl -i -k 'https://aip.baidubce.com/oaut...【百度云应用的AK】&client_secret=【百度云应用的SK】'
`

  1. AK和SK获取方式,需要通过创建一个应用,以个人的方式创建。

image.png

image.png

image.png

  1. rt-thread代码实现获取token
#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);  
    }  
}  
  1. Base64编码函数:
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;  
}  
  1. 图片UrlEncode:
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;  
}  
  1. rt-thread实现图片识别结果请求
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");  
}  
  1. 测试图片:

image.png

  1. 测试结果:

image.png

关注微信公众号『Rice嵌入式开发技术分享』,后台回复“微信”添加作者微信,备注”入群“,便可邀请进入技术交流群。

image.png
推荐阅读

更多嵌入式技术干货请关注Rice 嵌入式开发技术分享
推荐阅读
关注数
1756
内容数
51
一个周末很无聊的嵌入式软件工程师,写写经验,写写总结。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息