(簡單調用篇 02) 圖像主體檢測 - C++ 簡單調用

圖像主體檢測能檢測出圖片主體的座標位置,可使用該接口裁剪出圖像主體區域,配合圖像識別接口提升識別精度。廣泛適用於美圖類 app、輔助智能識圖等業務場景中。

應用場景

  • 智能美圖:根據用戶上傳照片進行主體檢測,實現圖像裁剪或背景虛化等功能,可應用於含美圖功能 app 等業務場景中
  • 圖像識別輔助:可使用圖像主體檢測裁剪出圖像主體區域,配合圖像識別接口提升識別精度

接口描述

用戶向服務請求檢測圖像中的主體位置。

請求說明

  • HTTP 方法: POST
  • 請求 URL: https://aip.baidubce.com/rest/2.0/image-classify/v1/object_detect
  • URL參數: access_token
  • Header 參數: Content-Type = application/x-www-form-urlencoded
  • Body 參數:見下表
參數 是否必選 類型 可選值範圍 說明
image true string - 圖像數據,base64 編碼,要求 base64 編碼後大小不超過 4M,最短邊至少 15px,最長邊最大 4096px,支持 jpg/png/bmp 格式 。注意:圖片需要 base64 編碼、去掉編碼頭後再進行 urlencode
with_face false number - 如果檢測主體是人,主體區域是否帶上人臉部分,0 - 不帶人臉區域,其他 - 帶人臉區域,裁剪類需求推薦帶人臉,檢索/識別類需求推薦不帶人臉。默認取 1,帶人臉

返回說明

返回參數如下表:

字段 是否必選 類型 說明
log_id uint64 唯一的 log id,用於問題定位
result watermark-location 裁剪結果
+left uint32 表示定位位置的長方形左上頂點的水平座標
+top uint32 表示定位位置的長方形左上頂點的垂直座標
+width uint32 表示定位位置的長方形的寬度
+height uint32 表示定位位置的長方形的高度

返回示例如下:

{
  "log_id": 895582300,
  "result": {
    "width": 486,
    "top": 76,
    "left": 134,
    "height": 394
  }
}

C++ 代碼實現調用

這裏假設已經將環境配置好了,環境配置的文章可以參考 Windows 下使用 Vcpkg 配置百度 AI 圖像識別 C++開發環境(VS2017)

爲了方便,首先根據返回參數定義了一個結構體,該結構體包括了返回參數中的參數,如下:

struct ObjDetInfo {
	uint32_t left;
	uint32_t top;
	uint32_t width;
	uint32_t height;

	void print() {
		std::cout << std::setw(20) << std::setfill('-') << '\n';
		std::cout << "left: " << left << "\n";
		std::cout << "top: " << top << "\n";
		std::cout << "width: " << width << "\n";
		std::cout << "height: " << height << "\n";
	}

	void draw(cv::Mat &img) {
		cv::Rect rect(left, top, width, height);
		cv::rectangle(img, rect, cv::Scalar(255, 0, 255), 3);
	}
};

ObjInfo 結構體中,定義了一個 print 方法以打印獲取的結果,draw 方法以在圖像上畫出邊框。

然後定義了一個類來調用接口並獲取結果

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

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

	// only get first result
	void getResult(ObjDetInfo& 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 對象中包含請求的結果。

getResult 獲取請求的結果。


完整代碼如下

util.hutil.cpp 代碼參見 (簡單調用篇 01) 通用物體和場景識別高級版 - C++ 簡單調用

ObjectDetection.h 代碼如下:

#pragma once
#include <string>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "util.h"

struct ObjDetInfo {
	uint32_t left;
	uint32_t top;
	uint32_t width;
	uint32_t height;

	void print() {
		std::cout << std::setw(20) << std::setfill('-') << '\n';
		std::cout << "left: " << left << "\n";
		std::cout << "top: " << top << "\n";
		std::cout << "width: " << width << "\n";
		std::cout << "height: " << height << "\n";
	}

	void draw(cv::Mat &img) {
		cv::Rect rect(left, top, width, height);
		cv::rectangle(img, rect, cv::Scalar(255, 0, 255), 3);
	}
};

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

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

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


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

void objectDetectionTest();

ObjectDetection.cpp 代碼如下:

#include "ObjectDetection.h"



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


ObjectDetection::~ObjectDetection()
{
}

Json::Value ObjectDetection::request(std::string imgBase64, std::map<std::string, std::string>& 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;

	checkErrorWithExit(obj);

	return obj;
}

void ObjectDetection::getResult(ObjDetInfo & result)
{
	result.left = obj_["result"].get("left", "0").asInt();
	result.top = obj_["result"].get("top", "0").asInt();
	result.width = obj_["result"].get("width", "0").asInt();
	result.height = obj_["result"].get("height", "0").asInt();
}

void objectDetectionTest()
{
	std::cout << "size: " << sizeof(ObjDetInfo) << "\n";

	// 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<std::string, std::string> options;
	options["with_face"] = "0";


	Json::Value obj;
	ObjectDetection objDetObj;
	obj = objDetObj.request(img_base64, options);
	//std::cout << (obj.get("result", "null")) << std::endl;
	ObjDetInfo result;
	objDetObj.getResult(result);
	result.print();

	cv::Mat img = cv::imread(img_file);
	result.draw(img);
	cv::namedWindow("Object Detection", cv::WINDOW_NORMAL);
	cv::imshow("Object Detection", img);
	cv::waitKey();
}

main.cpp 代碼如下:

#include "util.h"
#include "ObjectDetection.h"
#include <stdlib.h>

int main() {
    objectDetectionTest();

	system("pause");
	return EXIT_SUCCESS;
}

運行結果

在這裏插入圖片描述

在這裏插入圖片描述

發佈了22 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章