RTThreadIoTOS · 2021年10月08日

基于ART-Pi实现的AI图像识别

image.png

开源地址:
https://github.com/liukangcc/ART-PI\_BAIDUAI

不用自己训练模型,也能进行 AI 图像识别;借助百度云平台,我们可以在 APT-Pi 上实现图像识别功能。

创建图像识别应用

1、打开链接 百度智能云, 申请账号;
2、打开控制台
image.png
3、打开图像识别
image.png
4、创建应用
image.png
5、获取 AK 和 SK
image.png

通用图像识别

该请求用于通用物体及场景识别,即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片中的多个物体及场景标签。

1、打开 image_classify.c 文件, 修改 access_token, 填入应用的 AK 和 SK;
image.png
2、在 SD 卡中放入要识别的图片;
3、编译下载;
4、在终端输入命令: baidu_ai cat.jpg
image.png

5、加入百度百科,使能宏定义:#define BD_AI_BAIKE,编译下载:
image.png

返回说明

返回参数
image.png

菜品识别

该请求用于菜品识别。即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片的菜品名称、卡路里信息、置信度。

1、修改 URL 为菜品识别:

1    index = strlen(BAIDU_AI_API[1]);
2    post_uri_size = index;
3    post_uri = rt_malloc(256);
4
5    rt_memcpy(post_uri, BAIDU_AI_API[1], post_uri_size);

2、编译下载;
3、识别结果:
image.png

返回说明

返回参数
image.png

监控报表

在百度服务端,可以查看 API 调用成功和失败的次数:
image.png

图像格式

图像格式转换流程:
image.png
1、百度 AI 支持的图像格式有:PNG、JPG、JPEG、BMP
2、原始的图片数据需要转换为 base64 编码
3、base64 编码的图片数据进行百分比编码

Base64 编码

请求图片需经过base64编码:图片的base64编码指将一副图片数据编码成一串字符串,使用该字符串代替图像地址。您可以首先得到图片的二进制,然后用Base64格式编码即可。

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。

Base64编码是从二进制到字符的过程,可用于在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

1   /* get token */
 2int get_ai_token(const char *uri, unsigned char *token)
 3{
 4    char *request = RT_NULL;
 5    int token_len = 0, index = 0;
 6
 7    cJSON* cjson_parse = RT_NULL;
 8    cJSON* cjson_token = RT_NULL;
 9
10    if (webclient_request(uri, RT_NULL, RT_NULL, (unsigned char **)&request) < 0)
11    {
12        rt_kprintf("webclient send get request failed.");
13        return -RT_ERROR;
14    }
15
16    rt_kprintf("webclient send get request by simplify request interface.\n");
17    rt_kprintf("webclient get response data: \n");
18
19    for (index = 0; index < rt_strlen(request); index++)
20    {
21        rt_kprintf("%c", request[index]);
22    }
23    rt_kprintf("\n");
24
25    cjson_parse = cJSON_Parse(request);
26    if(cjson_parse == RT_NULL)
27    {
28        LOG_E("parse fail.\n");
29        goto __exit;
30    }
31
32    cjson_token = cJSON_GetObjectItem(cjson_parse, "access_token");
33    if (cjson_token == RT_NULL)
34    {
35        LOG_E("get onject 'access_token' item fail.\n");
36        goto __exit;
37    }
38
39    LOG_D("get_token: %s\n", cjson_token->valuestring);
40    token_len = rt_strlen(cjson_token->valuestring);
41    rt_memcpy(token, cjson_token->valuestring, token_len);
42
43__exit:
44
45    if (cjson_parse)
46    {
47        cJSON_Delete(cjson_parse);
48        cjson_parse = RT_NULL;
49        cjson_token = RT_NULL;
50    }
51
52    if (request)
53    {
54        web_free(request);
55    }
56
57    return token_len;
58}

图片数据编码

Base 64

 1static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 2
 3/* encode image */
 4int base64_encode(unsigned char * bytes_to_encode, unsigned char *encode, int bytes_len)
 5{
 6    int i = 0, j = 0, encode_size = 0;
 7    unsigned char char_array_3[3];
 8    unsigned char char_array_4[4];
 9
10    while (bytes_len--)
11    {
12        char_array_3[i++] = *(bytes_to_encode++);
13
14        if (i == 3)
15        {
16            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
17            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
18            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
19            char_array_4[3] = char_array_3[2] & 0x3f;
20
21            for(i = 0; i < 4; i++)
22            {
23                encode[encode_size++] = base64_chars[char_array_4[i]];
24            }
25            i = 0;
26        }
27    }
28
29    if (i)
30    {
31        for (j = i; j < 3; j++)
32        {
33            char_array_3[j] = '\0';
34        }
35
36        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
37        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
38        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
39        char_array_4[3] = char_array_3[2] & 0x3f;
40
41        for(j = 0; (j < i + 1); j++)
42        {
43            encode[encode_size++] = base64_chars[char_array_4[j]];
44        }
45
46        while ((i++ < 3))
47        {
48            encode[encode_size++] = '=';
49        }
50    }
51
52    return encode_size;
53}

百分比编码

1int http_percentage_coding(unsigned char *org_data, unsigned char *new_data, int len)
  2{
  3    int i = 0;
  4    unsigned char org_char = 0;
  5
  6    while (len--)
  7    {
  8        org_char = *(org_data++);
  9        switch (org_char)
 10        {
 11        case ':' :
 12            new_data[i++] = '%';
 13            new_data[i++] = '3';
 14            new_data[i++] = 'A';
 15        break;
 16
 17        case '/' :
 18            new_data[i++] = '%';
 19            new_data[i++] = '2';
 20            new_data[i++] = 'F';
 21        break;
 22
 23        case '?' :
 24            new_data[i++] = '%';
 25            new_data[i++] = '3';
 26            new_data[i++] = 'F';
 27        break;
 28
 29        case '#' :
 30            new_data[i++] = '%';
 31            new_data[i++] = '2';
 32            new_data[i++] = '3';
 33        break;
 34
 35        case '[' :
 36            new_data[i++] = '%';
 37            new_data[i++] = '5';
 38            new_data[i++] = 'B';
 39        break;
 40
 41        case ']' :
 42            new_data[i++] = '%';
 43            new_data[i++] = '5';
 44            new_data[i++] = 'D';
 45        break;
 46
 47        case '@' :
 48            new_data[i++] = '%';
 49            new_data[i++] = '4';
 50            new_data[i++] = '0';
 51        break;
 52
 53        case '!' :
 54            new_data[i++] = '%';
 55            new_data[i++] = '2';
 56            new_data[i++] = '1';
 57        break;
 58
 59        case '$' :
 60            new_data[i++] = '%';
 61            new_data[i++] = '2';
 62            new_data[i++] = '4';
 63        break;
 64
 65        case '&' :
 66            new_data[i++] = '%';
 67            new_data[i++] = '2';
 68            new_data[i++] = '6';
 69        break;
 70
 71        case '\'' :
 72            new_data[i++] = '%';
 73            new_data[i++] = '2';
 74            new_data[i++] = '7';
 75        break;
 76
 77        case '(' :
 78            new_data[i++] = '%';
 79            new_data[i++] = '2';
 80            new_data[i++] = '8';
 81        break;
 82
 83        case ')' :
 84            new_data[i++] = '%';
 85            new_data[i++] = '2';
 86            new_data[i++] = '9';
 87        break;
 88
 89        case '*' :
 90            new_data[i++] = '%';
 91            new_data[i++] = '2';
 92            new_data[i++] = 'A';
 93        break;
 94
 95        case '+' :
 96            new_data[i++] = '%';
 97            new_data[i++] = '2';
 98            new_data[i++] = 'B';
 99        break;
100
101        case ',' :
102            new_data[i++] = '%';
103            new_data[i++] = '2';
104            new_data[i++] = 'C';
105        break;
106
107        case ';' :
108            new_data[i++] = '%';
109            new_data[i++] = '3';
110            new_data[i++] = 'B';
111        break;
112
113        case '=' :
114            new_data[i++] = '%';
115            new_data[i++] = '3';
116            new_data[i++] = 'D';
117        break;
118
119        case '%' :
120            new_data[i++] = '%';
121            new_data[i++] = '2';
122            new_data[i++] = '5';
123        break;
124
125        case ' ' :
126            new_data[i++] = '%';
127            new_data[i++] = '2';
128            new_data[i++] = '0';
129        break;
130
131        default:
132            new_data[i++] = org_char;
133        break;
134        }
135    }
136    return i;
137}

获取识别结果

1int get_ai_result(const char *uri, const char *post_data, int post_data_size)
 2{
 3    struct webclient_session* session = RT_NULL;
 4    unsigned char *buffer = RT_NULL;
 5    int index, result = 0, resp_status, bytes_read;
 6
 7    buffer = (unsigned char *)web_malloc(POST_RESP_BUFSZ);
 8    if (buffer == RT_NULL)
 9    {
10        rt_kprintf("no memory for receive response buffer.\n");
11        result = -RT_ENOMEM;
12        goto __exit;
13    }
14
15    /* create webclient session and set header response size */
16    session = webclient_session_create(POST_HEADER_BUFSZ);
17    if (session == RT_NULL)
18    {
19        result = -RT_ENOMEM;
20        goto __exit;
21    }
22
23    /*  add http header */
24    webclient_header_fields_add(session, "Content-Length: %d\r\n", post_data_size);
25    webclient_header_fields_add(session, "Content-Type: application/x-www-form-urlencoded\r\n");
26
27    /* send POST request by default header */
28    if ((resp_status = webclient_post(session, uri, (const char *)post_data)) != 200)
29    {
30        LOG_E("webclient POST request failed, response(%d) error.\n", resp_status);
31        result = -RT_ERROR;
32        goto __exit;
33    }
34
35    rt_kprintf("webclient post response data: \n");
36    do
37    {
38        bytes_read = webclient_read(session, buffer, POST_RESP_BUFSZ);
39        if (bytes_read <= 0)
40        {
41            break;
42        }
43        for (index = 0; index < bytes_read; index++)
44        {
45            rt_kprintf("%c", buffer[index]);
46        }
47
48    } while (1);
49
50    rt_kprintf("\n");
51
52__exit:
53    if (session)
54    {
55        webclient_close(session);
56    }
57
58    if (buffer)
59    {
60        web_free(buffer);
61    }
62
63    return result;  
64}
原文链接:RTThread物联网操作系统
作者:Papalymo

推荐阅读
【AI简报20210917期】自研IP出货将超1亿片、北邮等利用超分算法提出高性能视频传输方法
【AI简报20210910期】联想发布LA2智能嵌入式控制器、单目摄像头实时感知车辆形状
【奇思妙想】0.1元成本柿饼派实现红外控制空调了

推荐阅读
关注数
8062
内容数
181
小而美的物联网操作系统,经过14年的累积发展,RT-Thread 已经拥有一个国内最大的嵌入式开源社区,同时被广泛应用于能源、车载、医疗、消费电子等多个行业,累积装机量超过4亿台,成为国人自主开发、国内最成熟稳定和装机量最大的开源 RTOS。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息