图像识别 C++ API接口调用(调用篇04)
busyboxs 发布于2020-11 浏览:1719 回复:0
1
收藏

同步链接: https://yangshun.win/blogs/95423fdc/

github code: https://github.com/busyboxs/BaiDuAICPP

植物识别支持识别超过 2 万种通用植物和近 8 千种花卉,接口返回植物的名称,并获取百科信息,适用于拍照识图类 APP 中。

应用场景

  • 拍照识图:根据拍摄照片,识别图片中植物的名称,可配合其它识图能力对识别的结果进一步细化,提高用户体验,广泛应用于拍照识图类 APP 中

接口描述

用于识别一张图片,即对于输入的一张图片(可正常解码,且长宽比较合适),输出植物识别结果。

请求说明

  • HTTP 方法: POST
  • 请求 URL: https://aip.baidubce.com/rest/2.0/image-classify/v1/plant
  • URL参数: access_token
  • Header 参数: Content-Type = application/x-www-form-urlencoded
  • Body 参数:见下表

返回说明

返回参数如下表:

返回示例如下:

{
	"log_id": 1705495792822072357,
	"result": [{
		"score": 0.99979120492935,
		"name": "莲",
		"baike_info": {
			"baike_url": "http://baike.baidu.com/item/%E8%8E%B2/2717141",
			"description": "莲(Nelumbo nucifera),又称荷、荷花、莲花、芙蕖、鞭蓉、水芙蓉、水芝、水芸、水旦、水华等,溪客、玉环是其雅称,未开的花蕾称菡萏,已开的花朵称鞭蕖,莲科,属多年生水生宿根草本植物,其地下茎称藕,能食用,叶入药,莲子为上乘补品,花可供观赏。是我国十大名花之一。是印度的国花。莲,双子叶植物,睡莲科。多年生挺水草本植物。根状茎横走,粗而肥厚,节间膨大,内有纵横通气孔道,节部缢缩。叶基生,挺出水面,盾形,直径30-90cm,波状边缘,上面深绿色,下面浅绿色。叶柄有小刺,长1-2m,挺出水面。花单生,直径10-25cm,椭圆花瓣多数,白色或粉红色;花柄长1-2m。花托在果期膨大,直径5-10cm,海绵质。坚果椭圆形和卵圆形,长1.5-2.0cm,灰褐色。种子卵圆形,长1.2-1.7cm,种皮红棕色。生于池塘、浅湖泊及稻田中。中国南北各省有自生或栽培,经济价值高。人们习惯上称种子为“莲子”、地下茎为“藕”、花托为“莲蓬”、叶为“荷叶”。"
		}
	},
	{
		"score": 0.00015144718054216,
		"name": "红睡莲"
	},
	{
		"score": 1.2172759852547e-05,
		"name": "白睡莲"
	},
	{
		"score": 6.305016540864e-06,
		"name": "延药睡莲"
	},
	{
		"score": 3.6133328649157e-06,
		"name": "华夏慈姑"
	}]
}

C++ 代码实现调用

这里假设已经将环境配置好了,环境配置的文章可以参考 Windows 下使用 Vcpkg 配置百度 AI 图像识别 C++开发环境(VS2017)[https://yangshun.win/blogs/3b103680/]。

为了方便,首先根据返回参数定义了一个结构体,该结构体包括了返回参数中的参数,如下:

struct PlantInfo {
	std::string name;
	float 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(6) << 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";
	}
};

在 PlantInfo 结构体中,定义了一个 print 方法以打印获取的结果。

然后定义了一个类来调用接口并获取结果

class Plant
{
public:
	Plant();
	~Plant();

	Json::Value request(std::string imgBase64, std::map& options);

	// get all return results
	void getAllResult(std::vector& results);

	// only get first result
	void getResult(PlantInfo& result);


private:
	Json::Value obj_;
	std::string url_;
	// file to save token key
	std::string filename_;
};

类中的私有成员 obj_ 表示返回结果对应的 json 对象。url_ 表示请求的 url,filename_ 表示用于存储 access token 的文件的文件名。

request 函数输入请求图像的 base64 编码以及请求参数,返回一个 json 对象,json 对象中包含请求的结果。

getAllResult 获取请求的结果,总共有 top_num 条结果。

getResult 获取 score 最高的一条结果。

完整代码如下

util.h 和 util.cpp 代码参见 (简单调用篇 01) 通用物体和场景识别高级版 - C++ 简单调用[https://yangshun.win/blogs/cd08a730/]

Plant.h 代码如下:

#pragma once
#include "util.h"

struct PlantInfo {
    std::string name;
    float 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(6) << 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 Plant
{
public:
    Plant();
    ~Plant();

    Json::Value request(std::string imgBase64, std::map& options);

    // get all return results
    void getAllResult(std::vector& results);

    // only get first result
    void getResult(PlantInfo& result);


private:
    Json::Value obj_;
    std::string url_;
    // file to save token key
    std::string filename_;
};

void plantTest();

Plant.cpp 代码如下:

#include "Plant.h"



Plant::Plant()
{
	filename_ = "tokenKey";
	url_ = "https://aip.baidubce.com/rest/2.0/image-classify/v1/plant";
}


Plant::~Plant()
{
}

Json::Value Plant::request(std::string imgBase64, std::map& options)
{
	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;
	// check for other error code
	checkErrorWithExit(obj);

	return obj;
}

void Plant::getAllResult(std::vector& results)
{
	int len = obj_["result"].size();
	results.reserve(len);
	PlantInfo tmp;

	for (int i = 0; i < len; ++i) {
		tmp.name = UTF8ToGB(obj_["result"][i]["name"].asString().c_str());
		tmp.score = obj_["result"][i]["score"].asFloat();
		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 Plant::getResult(PlantInfo & result)
{
	result.name = UTF8ToGB(obj_["result"][0]["name"].asString().c_str());
	result.score = obj_["result"][0]["score"].asFloat();
	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 plantTest()
{

	std::cout << "size: " << sizeof(PlantInfo) << "\n";

	// read image and encode to base64
	std::string imgFile = "./images/plant_test.jpg";
	std::string imgBase64;
	imgToBase64(imgFile, imgBase64);

	// set options
	std::map options;
	options["baike_num"] = "5";


	Json::Value obj;
	Plant plantObj;
	obj = plantObj.request(imgBase64, options);

	PlantInfo result;
	plantObj.getResult(result);
	result.print();

	std::vector results;
	plantObj.getAllResult(results);

	for (auto & vec : results) {
		vec.print();
	}
}

main.cpp 代码如下:

#include "util.h"
#include "Plant.h"
#include 

int main() {
    plantTest();

    system("pause");
    return EXIT_SUCCESS;
}

运行结果

测试图像

收藏
点赞
1
个赞
TOP
切换版块