不用自己训练模型,也能进行 AI 图像识别;借助百度云平台,我们可以在 APT-Pi 上实现图像识别功能。 创建图像识别应用- 打开链接 百度智能云, 申请账号;
- 打开控制台
- 打开图像识别
- 创建应用
- 获取 AK 和 SK
通用图像识别该请求用于通用物体及场景识别,即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片中的多个物体及场景标签。 - 打开 image_classify.c 文件, 修改 access_token, 填入应用的 AK 和 SK;
- 在 SD 卡中放入要识别的图片;
- 编译下载;
- 在终端输入命令: baidu_ai cat.jpg
- 加入百度百科,使能宏定义:#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对应识别结果百科内容描述菜品识别该请求用于菜品识别。即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片的菜品名称、卡路里信息、置信度。 - 修改 URL 为菜品识别:
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); - 编译下载;
- 识别结果:
返回说明返回参数 字段是否必选类型说明
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 调用成功和失败的次数: 图像格式图像格式转换流程: - 百度 AI 支持的图像格式有:PNG、JPG、JPEG、BMP
- 原始的图片数据需要转换为 base64 编码
- 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
- /* 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: %sn", 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
- 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;
- }
复制代码
百分比编码
- 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 '
- [b]获取识别结果[/b][code]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: %drn", post_data_size);
- webclient_header_fields_add(session, "Content-Type: application/x-www-form-urlencodedrn");
- /* 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;
- }
复制代码
仓库地址
文章转载自:RT-Thread 论坛,作者:Thread_Liu
:
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;
}[/code]
获取识别结果
- 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: %drn", post_data_size);
- webclient_header_fields_add(session, "Content-Type: application/x-www-form-urlencodedrn");
- /* 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;
- }
复制代码
仓库地址
文章转载自:RT-Thread论坛,作者:Thread_Liu
|