5、编写 OpenVINO 应用程序(C++ 版)

前提条件

已经安装好 OpenVINO、Visual Studio 2017。

配置项目

  1. 新建项目 -> C++ Windows 桌面项目 -> Windows 桌面向导 -> 项目命名为 cats_dogs_infer -> 空项目 -> 确定:
    在这里插入图片描述

  2. 选中“空项目” -> 确定:
    在这里插入图片描述

  3. 右键源文件 -> 新建 cats_dogs_infer.cpp:
    在这里插入图片描述

  4. 右键项目 -> 属性 -> 配置选择“所有配置” -> 平台选择“所有平台”:

  • 输出目录: $(SolutionDir)bin\$(Platform)\$(Configuration)\
  • 中间目录: $(SolutionDir)Intermediate\$(Platform)\$(Configuration)\
    在这里插入图片描述
    修改完毕后点击应用。
  1. C/C++ -> 常规 -> 平台选中“x64”:
    附加包含目录:$(IE_DIR)\include; $(IE_DIR)\src\extension; $(IE_DIR)\samples\common; $(OPENCV_DIR)\include
    修改完毕后点击应用。
    在这里插入图片描述

  2. C/C++ -> 预处理器:
    预处理器定义中输入:_CRT_SECURE_NO_WARNINGS
    在这里插入图片描述

  3. 链接器 -> 常规:
    附加库目录:$(IE_DIR)\lib\intel64\$(Configuration); $(OPENCV_DIR)\lib
    在这里插入图片描述

  4. 链接器 -> 输入 -> 配置选中“Debug” -> 平台选中“x64”:
    附加依赖项中添加:
    inference_engined.lib; cpu_extension.lib; opencv_calib3d412d.lib; opencv_core412d.lib; opencv_dnn412d.lib; opencv_features2d412d.lib; opencv_flann412d.lib; opencv_gapi412d.lib; opencv_highgui412d.lib; opencv_imgcodecs412d.lib; opencv_imgproc412d.lib; opencv_ml412d.lib; opencv_objdetect412d.lib; opencv_photo412d.lib; opencv_stitching412d.lib; opencv_video412d.lib; opencv_videoio412d.lib
    修改完毕后点击应用。
    在这里插入图片描述

  5. 链接器 -> 输入 -> 配置选中“Release”-> 平台选中“x64”:
    附加依赖项中添加:inference_engine.lib; cpu_extension.lib; opencv_calib3d412.lib; opencv_core412.lib; opencv_dnn412.lib; opencv_features2d412.lib; opencv_flann412.lib; opencv_gapi412.lib; opencv_highgui412.lib; opencv_imgcodecs412.lib; opencv_imgproc412.lib; opencv_ml412.lib; opencv_objdetect412.lib; opencv_photo412.lib; opencv_stitching412.lib; opencv_video412.lib; opencv_videoio412.lib
    在这里插入图片描述
    其中 cpu_extension.lib 是 CPU 插件扩展库。

  • inference_engine.lib 是用于 Release 模式的 OpenVINO 推理引擎库函数,在 C:\Program Files (x86)\IntelSWTools\openvino_2019.3.334\deployment_tools\inference_engine\lib\intel64\Release 目录下。
  • inference_engined.lib 是用于 Debug 模式的 OpenVINO 推理引擎库函数,在 C:\Program Files (x86)\IntelSWTools\openvino_2019.3.334\deployment_tools\inference_engine\lib\intel64\Debug 目录下。
  • OpenCV 库函数在 C:\Program Files (x86)\IntelSWTools\openvino_2019.3.334\opencv\lib 文件夹中。有带后缀 ‘d’ 的,表示用于 Debug 模式,没有后缀 ‘d’ 的,表示用于 Release 模式。

编写程序

需要修改的地方:

  • IR_FileNameNoExt:设置成你电脑上优化后的模型的路径,不要带后缀,如:E:/1-tf_train/workspaces/cats_dogs/optimized_model/ssd_inception_v2_coco(ssd_inception_v2_coco 是模型的名字)
  • imageFile:用来测试的图片的路径
//包含必要的头文件
#include<string> //C++ string标准库
#include<inference_engine.hpp> //Inference Engine库
#include<samples/ocv_common.hpp>//OpenCV库及matU8ToBlob函数定义
#include<ext_list.hpp>//IE CPU扩展库
#include<time.h>//C time标准库

using namespace InferenceEngine;

//将OpenCV Mat对象中的图像数据传给为InferenceEngine Blob对象
void frameToBlob(const cv::Mat& frame, InferRequest::Ptr& inferRequest, const std::string& inputName) {
	/* 从OpenCV Mat对象中拷贝图像数据到InferenceEngine 输入Blob对象 */
	Blob::Ptr frameBlob = inferRequest->GetBlob(inputName);
	matU8ToBlob<uint8_t>(frame, frameBlob);
}
//配置推理计算设备,IR文件路径,图片路径,阈值和标签
std::string DEVICE = "CPU";
std::string IR_FileNameNoExt = "E:/1-tf_train/workspaces/cats_dogs/optimized_model/ssd_inception_v2_coco";
std::string imageFile = "E:/1-tf_train/workspaces/cats_dogs/images/train/cat.11.jpg";
float confidence_threshold = 0.7; //取值0~1
std::vector<std::string> labels = { "fake","cat","dog" }; //标签输入

int main(void) {
	// ------------------------------------------------------------------------------------------

	// --------------------------- 1. 载入硬件插件(Plugin) --------------------------------------
	Core ie;
	std::cout << "1.Load Plugin..." << std::endl;     //输出当前执行步骤信息
	std::cout << ie.GetVersions(DEVICE) << std::endl; //输出插件版本信息

	 /** 载入默认扩展库 **/
	if (DEVICE.find("CPU") != std::string::npos) {
		/**
		 * CPU扩展库包含自定义的MKLDNNPlugin层实现
		 * 这些没有被MKLDNN实现的自定义层对的网络层推理计算很有用
		**/
		ie.AddExtension(std::make_shared<Extensions::Cpu::CpuExtensions>(), "CPU");

	}
	// ----------------------------------------------------------------------------------

	// ------------------- 2. 读取IR文件 (.xml and .bin files) --------------------------
	std::cout << "2.Read IR File..." << std::endl;

	CNNNetReader networkReader;
	/** 读取神经网络模型文件*.xml **/
	networkReader.ReadNetwork(IR_FileNameNoExt + ".xml");
	/** 读取神经网络权重文件*.bin **/
	networkReader.ReadWeights(IR_FileNameNoExt + ".bin");
	/** 获取神经网络对象 **/
	CNNNetwork network = networkReader.getNetwork();
	// ----------------------------------------------------------------------------------

	// -------------------- 3. 配置网络输入输出 -----------------------------------------
	std::cout << "3.Prepare Input and Output..." << std::endl;
	/** 获得神经网络的输入信息 **/
	InputsDataMap inputsInfo(network.getInputsInfo());
	std::string imageInputName, imInfoInputName;
	InputInfo::Ptr inputInfo = nullptr;
	SizeVector inputImageDims;

	/** 遍历模型所有的输入blobs **/
	for (auto & item : inputsInfo) {
		/** 处理保存图像数据的第一个张量 **/
		if (item.second->getInputData()->getTensorDesc().getDims().size() == 4) {
			imageInputName = item.first;
			inputInfo = item.second;
			/** 创建第一个输入blob **/
			Precision inputPrecision = Precision::U8;
			item.second->setPrecision(inputPrecision);
		}
		else if (item.second->getInputData()->getTensorDesc().getDims().size() == 2) {
			imInfoInputName = item.first;
			Precision inputPrecision = Precision::FP32;
			item.second->setPrecision(inputPrecision);
			if ((item.second->getTensorDesc().getDims()[1] != 3 && item.second->getTensorDesc().getDims()[1] != 6)) {
				throw std::logic_error("Invalid input info. Should be 3 or 6 values length");
			}
		}
	}
	/** 获得神经网络的输出信息 **/
	OutputsDataMap outputsInfo(network.getOutputsInfo());
	std::string outputName;
	DataPtr outputInfo;
	for (const auto& out : outputsInfo) {
		if (out.second->getCreatorLayer().lock()->type == "DetectionOutput") {
			outputName = out.first;
			outputInfo = out.second;
		}
	}
	const SizeVector outputDims = outputInfo->getTensorDesc().getDims();
	const int maxProposalCount = outputDims[2];
	const int objectSize = outputDims[3];
	outputInfo->setPrecision(Precision::FP32);
	// --------------------------------------------------------------------------------------------

	// --------------------------- 4. 载入模型到AI推理计算设备---------------------------------------
	std::cout << "4.Load model into device..." << std::endl;
	ExecutableNetwork executable_network = ie.LoadNetwork(network, DEVICE, {});

	// --------------------------------------------------------------------------------------------

	// --------------------------- 5. 创建Infer Request--------------------------------------------
	std::cout << "5.Create Infer Request..." << std::endl;
	InferRequest::Ptr infer_request = executable_network.CreateInferRequestPtr();

	// --------------------------------------------------------------------------------------------

	// --------------------------- 6. 准备输入数据 ------------------------------------------------
	std::cout << "6.Prepare Input..." << std::endl;
	cv::Mat img = cv::imread(imageFile);
	frameToBlob(img, infer_request, imageInputName);
	const size_t width = (size_t)img.cols;
	const size_t height = (size_t)img.rows;
	// --------------------------------------------------------------------------------------------

	// --------------------------- 7. 执行推理计算 ------------------------------------------------
	std::cout << "7.Start inference..." << std::endl;
	std::clock_t begin, end;
	begin = std::clock();
	infer_request->Infer();
	end = std::clock();
	std::ostringstream infer_time;//计算推理计算所花费的时间
	infer_time << "Infer Time:" << (double)(end - begin) << "ms";
	cv::putText(img, infer_time.str(), cv::Point2f(0, 12), cv::FONT_HERSHEY_TRIPLEX, 0.6, cv::Scalar(0, 255, 0));
	// --------------------------------------------------------------------------------------------

	// --------------------------- 8. 处理输出 ----------------------------------------------------
	std::cout << "8.Process output blobs..." << std::endl;
	
	
	
	const float *detections = infer_request->GetBlob(outputName)->buffer().as<PrecisionTrait<Precision::FP32>::value_type*>();
	
	for (int i = 0; i < maxProposalCount; i++) {

		float image_id = detections[i * objectSize + 0];

		float confidence = detections[i * objectSize + 2];
		auto label = static_cast<int>(detections[i * objectSize + 1]);
		float xmin = detections[i * objectSize + 3] * width;
		float ymin = detections[i * objectSize + 4] * height;
		float xmax = detections[i * objectSize + 5] * width;
		float ymax = detections[i * objectSize + 6] * height;
		
		if (confidence > confidence_threshold) {
			// 仅当> confidence_threshold值时,显示推理计算结果
			std::ostringstream conf;
			conf << ":" << std::fixed << std::setprecision(3) << confidence;
			
			if (xmin < 0) {
				xmin = -xmin;
			}
			if (ymin < 0) {
				ymin = -ymin;
			}
			if (xmax > width) {
				xmax = width;
			}
			if (ymax > height) {
				ymax = height;
			}
			cv::Point origin;
			origin.x = xmin;
			origin.y = ymin + 20;
			
			std::cout << label << std::endl;
			std::string text = "UNKNOWN";
			if (1 <= label && label <= 2) {
				text = labels[label];
			}
			cv::putText(img, text,
				origin, cv::FONT_HERSHEY_COMPLEX_SMALL, 1,
				cv::Scalar(0, 0, 255));
			cv::rectangle(img, cv::Point2f(xmin, ymin), cv::Point2f(xmax, ymax), cv::Scalar(0, 0, 255));
		}
		
	}
	
	std::cout << "Infer done!" << std::endl;
	cv::imshow("Detection results", img);
	cv::waitKey(0);
	cv::destroyAllWindows();

	return 0;
}

编译执行

完成 cats_dogs_infer.cpp 代码后,将解决方案配置设置为 Release 和 x64,然后点击本地 Windows 调试器,编译并运行 cats_dogs_infer 程序。

切换 AI 推理计算硬件

英特尔所有的 AI 计算硬件都使用统一的 OpenVINO 工具套件进行应用程序开发,在切换硬件的时候,不需要修改一行代码,只需更改插件名称,即可完成 AI 推理硬件的切换。

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值