同步链接: https://yangshun.win/blogs/cb803aa6/
github code: https://github.com/busyboxs/BaiDuAICPP
动物识别能够识别近八千种动物,接口返回动物名称,并获取百科信息,适用于拍照识图类APP中。
应用场景
- 拍照识别:根据拍摄照片,识别图片中动物的名称,可配合其它识图能力对识别的结果进一步细化,提高用户体验,广泛应用于拍照识图类APP中
接口描述
用于识别一张图片,即对于输入的一张图片(可正常解码,且长宽比较合适),输出动物识别结果。
请求说明
- HTTP 方法: POST
- 请求 URL: https://aip.baidubce.com/rest/2.0/image-classify/v1/animal
- URL参数: access_token
- Header 参数: Content-Type = application/x-www-form-urlencoded
- Body 参数:见下表
返回说明
返回参数如下表:
返回示例如下:
{ "log_id": 7392482912853822863, "result": [{ "score": "0.993811", "name": "叉角羚", "baike_info": { "baike_url": "http://baike.baidu.com/item/%E5%8F%89%E8%A7%92%E7%BE%9A/801703", "description": "叉角羚(学名:Antilocapra americana):在角的中部角鞘有向前伸的分枝,故名。体型中等,体长1-1.5米,尾长7.5-10厘米,肩高81-104厘米,成体重36-60千克,雌体比雄体小;背面为红褐色,颈部有黑色鬃毛,腹部和臀部为白色,颊面部和颈部两侧有黑色块斑;毛被下面为绒毛,上覆以粗糙、质脆的长毛,由于某些皮肤肌的作用,能使其毛被呈不同角度,以利于保暖或散热。植食。叉角羚奔跑速度非常快,最高时速达100千米。一次跳跃可达3.5-6米。善游泳。夏季组成小群活动,冬季则集结成上百只的大群。为寻找食物和水源,一年中常进行几次迁移。性机警,视觉敏锐,能看到数千米外的物体。遇险时,臀部的白色毛能立起,向同伴告警。分布于北美洲。" } }, { "score": "0.000289439", "name": "印度羚" }, { "score": "0.000186248", "name": "藏羚羊" }, { "score": "0.000147176", "name": "跳羚" }, { "score": "0.000134434", "name": "驯鹿" }, { "score": "9.86555e-05", "name": "高鼻羚羊" }] }
C++ 代码实现调用
这里假设已经将环境配置好了,环境配置的文章可以参考 Windows 下使用 Vcpkg 配置百度 AI 图像识别 C++开发环境(VS2017)[https://yangshun.win/blogs/3b103680/]。
为了方便,首先根据返回参数定义了一个结构体,该结构体包括了返回参数中的参数,如下:
struct AnimalInfo { std::string name; std::string score; std::string baikeurl; std::string imageurl; std::string baikedesc; void print() { std::cout << std::setw(30) << std::setfill('-') << '\n'; std::cout << "name: " << name << "\n"; std::cout << "score: " << std::fixed << std::setprecision(4) << std::stof(score) << "\n"; if (baikeurl != "null") std::cout << "baikeurl: " << baikeurl << "\n"; if (imageurl != "null") std::cout << "imageurl: " << imageurl << "\n"; if (baikedesc != "null") std::cout << "baikedesc: " << baikedesc << "\n"; } };
在 AnimalInfo 结构体中,定义了一个 print 方法以打印获取的结果。
然后定义了一个类来调用接口并获取结果
class Animal { public: Animal(); ~Animal(); Json::Value request(std::string imgBase64, std::map& options); // get all return results void getAllResult(std::vector& results); // only get first result void getResult(AnimalInfo& result); private: Json::Value obj_; std::string url_; int top_num_; // file to save token key std::string filename_; };
类中的私有成员 obj_ 表示返回结果对应的 json 对象。url_ 表示请求的 url,top_num_ 表示请求参数中对应的 top_num,filename_ 表示用于存储 access token 的文件的文件名。
request 函数输入请求图像的 base64 编码以及请求参数,返回一个 json 对象,json 对象中包含请求的结果。
getAllResult 获取请求的结果,总共有 top_num 条结果。
getResult 获取 score 最高的一条结果。
完整代码如下
util.h 和 util.cpp 代码参见 (简单调用篇 01) 通用物体和场景识别高级版 - C++ 简单调用[https://yangshun.win/blogs/cb803aa6/]
Animal.h 代码如下:
#pragma once #include #include #include #include #include #include #include #include "util.h" struct AnimalInfo { std::string name; std::string score; std::string baikeurl; std::string imageurl; std::string baikedesc; void print() { std::cout << std::setw(30) << std::setfill('-') << '\n'; std::cout << "name: " << name << "\n"; std::cout << "score: " << std::fixed << std::setprecision(4) << std::stof(score) << "\n"; if (baikeurl != "null") std::cout << "baikeurl: " << baikeurl << "\n"; if (imageurl != "null") std::cout << "imageurl: " << imageurl << "\n"; if (baikedesc != "null") std::cout << "baikedesc: " << baikedesc << "\n"; } }; class Animal { public: Animal(); ~Animal(); Json::Value request(std::string imgBase64, std::map& options); // get all return results void getAllResult(std::vector& results); // only get first result void getResult(AnimalInfo& result); private: Json::Value obj_; std::string url_; int top_num_; // file to save token key std::string filename_; }; void animalTest();
Animal.cpp 代码如下:
#include "animal.h" Animal::Animal() { url_ = "https://aip.baidubce.com/rest/2.0/image-classify/v1/animal"; top_num_ = 6; // default value } Animal::~Animal() { } Json::Value Animal::request(std::string imgBase64, std::map& options) { if (!options["top_num"].empty()) { top_num_ = std::stoi(options["top_num"]); } std::string response; Json::Value obj; std::string token; // 1. get HTTP post body std::string body; mergeHttpPostBody(body, imgBase64, options); // 2. get HTTP url with access token std::string url = url_; getHttpPostUrl(url, filename_, token); // 3. post request, response store the result int status_code = httpPostRequest(url, body, response); if (status_code != CURLcode::CURLE_OK) { obj["curl_error_code"] = status_code; obj_ = obj; return obj; // TODO: maybe should exit } // 4. make string to json object generateJson(response, obj); // if access token is invalid or expired, we will get a new one 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 Animal::getAllResult(std::vector& results) { results.reserve(top_num_); AnimalInfo tmp; for (int i = 0; i < top_num_; ++i) { tmp.name = UTF8ToGB(obj_["result"][i]["name"].asString().c_str()); tmp.score = obj_["result"][i]["score"].asString(); tmp.baikeurl = obj_["result"][i]["baike_info"].get("baike_url", "null").asString(); tmp.imageurl = obj_["result"][i]["baike_info"].get("image_url", "null").asString(); tmp.baikedesc = UTF8ToGB(obj_["result"][i]["baike_info"].get("description", "null").asString().c_str()); results.push_back(tmp); } } void Animal::getResult(AnimalInfo & result) { result.name = UTF8ToGB(obj_["result"][0]["name"].asString().c_str()); result.score = obj_["result"][0]["score"].asString(); result.baikeurl = obj_["result"][0]["baike_info"].get("baike_url", "null").asString(); result.imageurl = obj_["result"][0]["baike_info"].get("image_url", "none").asString(); result.baikedesc = UTF8ToGB(obj_["result"][0]["baike_info"].get("description", "none").asString().c_str()); } void animalTest() { // read image and encode to base64 std::string img_file = "./images/cat.jpg"; std::string out; readImageFile(img_file.c_str(), out); std::string img_base64 = base64_encode(out.c_str(), (int)out.size()); // set options std::map options; options["top_num"] = "5"; options["baike_num"] = "5"; Json::Value obj; Animal animalObj; AnimalInfo result; obj = animalObj.request(img_base64, options); animalObj.getResult(result); result.print(); std::vector results; animalObj.getAllResult(results); for (auto & vec : results) { vec.print(); } }
main.cpp 代码如下:
#include "util.h" #include "Animal.h" #include int main() { animalTest(); system("pause"); return EXIT_SUCCESS; }
运行结果
测试图像