红酒识别能识别图像中的红酒标签,返回红酒名称、国家、产区、酒庄、类型、糖分、葡萄品种、酒品描述等信息,可识别数十万中外红酒
应用场景
红酒介绍与推荐:识别用户拍摄图片中的红酒,提供详细的红酒介绍,同时可结合识别结果进一步为用户提供商品推荐、营养搭配等服务,适用于酒类电商平台、红酒展销、拍照识图软件、美食健康APP等
接口描述
该服务用于识别红酒标签,即对于输入的一张图片(可正常解码,长宽比适宜,且酒标清晰可见),输出图片中的红酒名称、国家、产区、酒庄、类型、糖分、葡萄品种、酒品描述等信息。可识别数十万中外常见红酒。
请求说明
HTTP 方法: POST
请求 URL: https://aip.baidubce.com/rest/2.0/image-classify/v1/redwine
URL参数: access_token
Header 参数: Content-Type
= application/x-www-form-urlencoded
Body 参数:见下表
参数
是否必选
类型
默认值
说明
image
是
string
-
图像数据,base64
编码,要求 base64
编码后大小不超过 4M,最短边至少 15px
,最长边最大 4096px
, 支持 jpg/png/bmp
格式 。注意:图片需要 base64
编码、去掉编码头后再进行 urlencode
返回说明
返回参数如下表:
字段
是否必选
类型
说明
log_id
是
uint64
请求标识码,随机数,唯一
result
是
dict
识别结果
+hasdetail
是
unit
判断是否返回详细信息(除红酒中文名之外的其他字段),含有返回 1,不含有返回 0
+wineNameCn
是
string
红酒中文名,无法识别返回空,示例:波斯塔瓦经典赤霞珠品丽珠半甜红葡萄酒
+wineNameEn
否
string
红酒英文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:Bostavan Classic Cabernet
+countryCn
否
string
国家中文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:摩尔多瓦
+countryEn
否
string
国家英文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:Moldova
+regionCn
否
string
产区中文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:波尔多
+regionEn
否
string
产区英文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:Bordeaux
+subRegionCn
否
string
子产区中文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:梅多克
+subRegionEn
否
string
子产区英文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:Medoc
+wineryCn
否
string
酒庄中文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:波斯塔瓦酒庄
+wineryEn
否
string
酒庄英文名,hasdetail = 0
时,表示无法识别,该字段不返回,示例:Vinaria Bostavan
+classifyByColor
否
string
酒类型,hasdetail = 0
时,表示无法识别,该字段不返回,示例:红葡萄酒
+classifyBySugar
否
string
糖分类型,hasdetail = 0
时,表示无法识别,该字段不返回,示例:半甜型
+color
否
string
色泽,hasdetail = 0
时,表示无法识别,该字段不返回,示例:宝石红色
+grapeCn
否
string
葡萄品种,可能有多种葡萄,hasdetail = 0
时,表示无法识别,该字段不返回,示例:品丽珠;赤霞珠
+grapeEn
否
string
葡萄品种英文名,可能有多种葡萄,hasdetail = 0
时,表示无法识别,该字段不返回,示例:Cabernet Franc;Cabernet Sauvignon
+tasteTemperature
否
string
品尝温度,hasdetail = 0
时,表示无法识别,该字段不返回,示例:6-11℃
+description
否
string
酒品描述,hasdetail = 0
时,表示无法识别,该字段不返回,示例:葡萄酒呈深宝石红色,具有香料、香草和新鲜水果的果香,酒体分明,口感畅顺,果香横溢,单宁软化程度高,让你回味无穷
返回示例如下:
仅识别出红酒名称,hasdetail = 0
:
1 2 3 4 5 6 7 8 { "log_id" : 3450013152046070669 , "result" : { "wineNameCn" : "银色高地阙歌干红" , "hasdetail" :0 } }
识别出详细信息,hasdetail = 1
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 { "log_id" : 2495538539661269738 , "result" : { "classifyByColor" : "红葡萄酒/Red Wine" , "subRegionCn" : "梅多克" , "wineNameCn" : "拉图嘉利庄园红葡萄酒(正牌)" , "subRegionEn" : "Medoc" , "regionEn" : "Bordeaux" , "color" : "深紫红色/Dark Violet" , "wineNameEn" : "Chateau La Tour Carnet" , "hasdetail" : 1 , "wineryCn" : "拉图嘉利庄园" , "classifyBySugar" : "干型/Dry" , "tasteTemperature" : "16-18℃" , "regionCn" : "波尔多" , "wineryEn" : "Chateau La Tour-Carnet" , "grapeCn" : "" , "grapeEn" : "" , "countryCn" : "法国" , "countryEn" : "France" , "description" : "此酒充满红果和黑果味道,并带有矿物质和花香(紫罗兰,玫瑰),混合些许香草气息,单宁柔软,余香悠长。在口中留下清新的味道,香料和香草味道萦绕口中。" } }
C++ 代码实现调用
这里假设已经将环境配置好了,环境配置的文章可以参考 Windows 下使用 Vcpkg 配置百度 AI 图像识别 C++开发环境(VS2017) 。
为了方便,首先根据返回参数定义了一个结构体,该结构体包括了返回参数中的参数,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 struct RedwineInfo { bool hasdetail; std ::string wineNameCn; std ::string wineNameEn; std ::string countryCn; std ::string countryEn; std ::string regionCn; std ::string regionEn; std ::string subRegionCn; std ::string subRegionEn; std ::string wineryCn; std ::string wineryEn; std ::string classifyByColor; std ::string classifyBySugar; std ::string color; std ::string grapeCn; std ::string grapeEn; std ::string tasteTemperature; std ::string description; void print () { std ::cout << std ::setw(30 ) << std ::setfill('-' ) << '\n' ; std ::cout << "name: " << wineNameCn << " - " << wineNameEn << '\n' ; if (hasdetail) { std ::cout << "country: " << countryCn << " - " << countryEn << '\n' ; std ::cout << "region: " << countryCn << " - " << regionEn << '\n' ; std ::cout << "subregion: " << subRegionCn << " - " << subRegionEn << '\n' ; std ::cout << "winery: " << wineryCn << " - " << wineryEn << '\n' ; std ::cout << "classify by color: " << classifyByColor << '\n' ; std ::cout << "classify by sugar: " << classifyBySugar << '\n' ; std ::cout << "color: " << color << '\n' ; std ::cout << "grape: " << grapeCn << " - " << grapeEn << '\n' ; std ::cout << "taste temperature: " << tasteTemperature << '\n' ; std ::cout << "description: " << description << '\n' ; } } };
在 RedwineInfo
结构体中,定义了一个 print
方法以打印获取的结果。
然后定义了一个类来调用接口并获取结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Redwine { public : Redwine(); ~Redwine(); Json::Value request (std ::string imgBase64, std ::map <std ::string , std ::string >& options) ; void getResult (RedwineInfo& result) ; private : Json::Value obj_; std ::string url_; std ::string filename_; };
类中的私有成员 obj_
表示返回结果对应的 json 对象。url_
表示请求的 url,filename_
表示用于存储 access token
的文件的文件名。
request
函数输入请求图像的 base64 编码以及请求参数,返回一个 json 对象,json 对象中包含请求的结果。
getResult
获取红酒识别结果。
完整代码如下
util.h
和 util.cpp
代码参见 (简单调用篇 01) 通用物体和场景识别高级版 - C++ 简单调用
Redwine.h
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #pragma once #include "util.h" struct RedwineInfo { bool hasdetail; std ::string wineNameCn; std ::string wineNameEn; std ::string countryCn; std ::string countryEn; std ::string regionCn; std ::string regionEn; std ::string subRegionCn; std ::string subRegionEn; std ::string wineryCn; std ::string wineryEn; std ::string classifyByColor; std ::string classifyBySugar; std ::string color; std ::string grapeCn; std ::string grapeEn; std ::string tasteTemperature; std ::string description; void print () { std ::cout << std ::setw(30 ) << std ::setfill('-' ) << '\n' ; std ::cout << "name: " << wineNameCn << " - " << wineNameEn << '\n' ; if (hasdetail) { std ::cout << "country: " << countryCn << " - " << countryEn << '\n' ; std ::cout << "region: " << countryCn << " - " << regionEn << '\n' ; std ::cout << "subregion: " << subRegionCn << " - " << subRegionEn << '\n' ; std ::cout << "winery: " << wineryCn << " - " << wineryEn << '\n' ; std ::cout << "classify by color: " << classifyByColor << '\n' ; std ::cout << "classify by sugar: " << classifyBySugar << '\n' ; std ::cout << "color: " << color << '\n' ; std ::cout << "grape: " << grapeCn << " - " << grapeEn << '\n' ; std ::cout << "taste temperature: " << tasteTemperature << '\n' ; std ::cout << "description: " << description << '\n' ; } } }; class Redwine { public : Redwine(); ~Redwine(); Json::Value request (std ::string imgBase64, std ::map <std ::string , std ::string >& options) ; void getResult (RedwineInfo& result) ; private : Json::Value obj_; std ::string url_; std ::string filename_; }; void redwineTest () ;
Redwine.cpp
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 #include "Redwine.h" Redwine::Redwine() { filename_ = "tokenKey" ; url_ = "https://aip.baidubce.com/rest/2.0/image-classify/v1/redwine" ; } Redwine::~Redwine() { } Json::Value Redwine::request (std ::string imgBase64, std ::map <std ::string , std ::string >& options) { std ::string response; Json::Value obj; std ::string token; std ::string body; mergeHttpPostBody(body, imgBase64, options); std ::string url = url_; getHttpPostUrl(url, filename_, token); int status_code = httpPostRequest(url, body, response); if (status_code != CURLcode::CURLE_OK) { obj["curl_error_code" ] = status_code; obj_ = obj; return obj; } generateJson(response, obj); if (obj["error_code" ].asInt() == 110 || obj["error_code" ].asInt() == 111 ) { token = getTokenKey(); writeFile(filename_, token); return request(imgBase64, options); } obj_ = obj; checkErrorWithExit(obj); return obj; } void Redwine::getResult (RedwineInfo & result) { result.hasdetail = obj_["result" ]["hasdetail" ].asBool(); result.wineNameCn = UTF8ToGB(obj_["result" ]["wineNameCn" ].asString().c_str()); result.wineNameEn = obj_["result" ]["wineNameEn" ].asString(); result.countryCn = UTF8ToGB(obj_["result" ]["countryCn" ].asString().c_str()); result.countryEn = obj_["result" ]["countryEn" ].asString(); result.regionCn = UTF8ToGB(obj_["result" ]["regionCn" ].asString().c_str()); result.regionEn = obj_["result" ]["regionEn" ].asString(); result.subRegionCn = UTF8ToGB(obj_["result" ]["subRegionCn" ].asString().c_str()); result.subRegionEn = obj_["result" ]["subRegionEn" ].asString(); result.wineryCn = UTF8ToGB(obj_["result" ]["wineryCn" ].asString().c_str()); result.wineryEn = obj_["result" ]["wineryEn" ].asString(); result.classifyByColor = UTF8ToGB(obj_["result" ]["classifyByColor" ].asString().c_str()); result.classifyBySugar = UTF8ToGB(obj_["result" ]["classifyBySugar" ].asString().c_str()); result.color = UTF8ToGB(obj_["result" ]["color" ].asString().c_str()); result.grapeCn = UTF8ToGB(obj_["result" ]["grapeCn" ].asString().c_str()); result.grapeEn = UTF8ToGB(obj_["result" ]["grapeEn" ].asString().c_str()); result.tasteTemperature = UTF8ToGB(obj_["result" ]["tasteTemperature" ].asString().c_str()); result.description = UTF8ToGB(obj_["result" ]["description" ].asString().c_str()); } void redwineTest () { std ::cout << "size: " << sizeof (RedwineInfo) << "\n" ; std ::string imgFile = "./images/wine.png" ; std ::string imgBase64; imgToBase64(imgFile, imgBase64); std ::map <std ::string , std ::string > options; Json::Value obj; Redwine redwineObj; obj = redwineObj.request(imgBase64, options); RedwineInfo result; redwineObj.getResult(result); result.print(); }
main.cpp
代码如下:
1 2 3 4 5 6 7 8 9 10 #include "util.h" #include "Redwine.h" #include <stdlib.h> int main () { redwineTest(); system("pause" ); return EXIT_SUCCESS; }
运行结果
测试图像