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

同步链接: https://yangshun.win/blogs/6baf7870/

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

果蔬识别能识别近千种水果和蔬菜的名称,适用于识别只含有一种果蔬的图片,可自定义返回识别结果数,适用于果蔬介绍相关的美食类APP中。

应用场景

  • 果蔬介绍:根据拍摄照片,识别图片中果蔬名称,可结合识别结果进一步为用户提供营养价值、搭配禁忌,果蔬推荐等相关信息,广泛应用于美食类APP中。

接口描述

该请求用于识别果蔬类食材,即对于输入的一张图片(可正常解码,且长宽比适宜),输出图片中的果蔬食材结果。

请求说明

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

返回说明

返回参数如下表:

返回示例如下:

{
    "log_id": 1091287364,
    "result_num": 20,
    "result": [
        {
            "name": "非果蔬食材",
            "score": 0.99999988079071
        },
        {
            "name": "油菜",
            "score": 1.1175458780599e-8
        },
        {
            "name": "蛇果",
            "score": 7.2776291659693e-9
        },
        {
            "name": "国光苹果",
            "score": 5.6971951600815e-9
        },
        {
            "name": "海枣",
            "score": 4.2508210285064e-9
        },
        {
            "name": "琼瑶浆葡萄",
            "score": 4.1451895249622e-9
        },
        {
            "name": "京锐号辣椒",
            "score": 3.9915102334476e-9
        },
        {
            "name": "冬瓜",
            "score": 3.3611948779821e-9
        },
        {
            "name": "长江豆",
            "score": 2.9944848822794e-9
        },
        {
            "name": "黑加仑",
            "score": 2.7750137743254e-9
        },
        {
            "name": "面包果",
            "score": 2.3357531464541e-9
        },
        {
            "name": "椰子",
            "score": 1.9741890344704e-9
        },
        {
            "name": "美人瓜",
            "score": 1.9319581490151e-9
        },
        {
            "name": "莲藕",
            "score": 1.759222323372e-9
        },
        {
            "name": "黑奥林",
            "score": 1.7266311713726e-9
        },
        {
            "name": "芥菜",
            "score": 1.6180708994895e-9
        },
        {
            "name": "样芹菜",
            "score": 1.5472728653876e-9
        },
        {
            "name": "篙巴",
            "score": 1.4084827748562e-9
        },
        {
            "name": "花生",
            "score": 1.3972580870103e-9
        },
        {
            "name": "魁绿猕猴桃",
            "score": 1.3920842256709e-9
        }
    ]
}

C++ 代码实现调用

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

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

struct IngredientInfo {
	std::string name;
	double score;

	void print() {
		std::cout << std::setw(30) << std::setfill('-') << '\n';
		std::cout << "name: " << name << '\n';
		std::cout << "score: " << score << '\n';
	}
};

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

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

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

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

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

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


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

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

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

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

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

完整代码如下

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

Ingredient.h 代码如下:

#pragma once
#include "util.h"

struct IngredientInfo {
	std::string name;
	double score;

	void print() {
		std::cout << std::setw(30) << std::setfill('-') << '\n';
		std::cout << "name: " << name << '\n';
		std::cout << "score: " << score << '\n';
	}
};

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

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

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

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


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

void ingredientTest();

Ingredient.cpp 代码如下:

#include "Ingredient.h"



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


Ingredient::~Ingredient()
{
}

Json::Value Ingredient::request(std::string imgBase64, std::map& options)
{
	if (options.find("top_num") == options.end()) { // if top_num param is empty
		top_num_ = 5;
	}
	else {
		int top_num = stoi(options["top_num"]);
		top_num_ = top_num <= 0 ? 5 : (top_num >= 20 ? 20 : 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;
	// check for other error code
	checkErrorWithExit(obj);

	return obj;
}

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

	for (int i = 0; i < len; ++i) {
		tmp.name = UTF8ToGB(obj_["result"][i]["name"].asString().c_str());
		tmp.score = obj_["result"][i]["score"].asDouble();

		results.push_back(tmp);
	}
}

void Ingredient::getResult(IngredientInfo & result)
{
	result.name = UTF8ToGB(obj_["result"][0]["name"].asString().c_str());
	result.score = obj_["result"][0]["score"].asDouble();
}

void ingredientTest() {
	std::cout << "size: " << sizeof(IngredientInfo) << "\n";

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

	// set options
	std::map options;
	options["top_num"] = "10";


	Json::Value obj;
	Ingredient ingredientObj;
	obj = ingredientObj.request(imgBase64, options);

	IngredientInfo result;
	ingredientObj.getResult(result);
	result.print();

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

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

main.cpp 代码如下:

#include "util.h"
#include "Ingredient.h"
#include 

int main() {
    ingredientTest();

    system("pause");
    return EXIT_SUCCESS;
}

运行结果

测试图像

 

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