OpenCV4入门140:DNN模块的模型运行设置目标设备与计算后台

索引地址:系列索引

OpenCV中加载网络模型之后,可以设置计算后台与计算目标设备,OpenCV DNN模块支持这两个设置的相关API如下:

计算后台

1
void cv::dnn::Net::setPreferableBackend (int backendId);

backendId 表示后台计算,常见参数如下:

  • DNN_BACKEND_DEFAULT (DNN_BACKEND_INFERENCE_ENGINE):表示默认使用intel的预测推断库(需要下载安装Intel® OpenVINO™ toolkit, 然后重新编译OpenCV源码,在CMake时候enable该选项方可), 可加速计算;
  • DNN_BACKEND_HALIDE
  • DNN_BACKEND_INFERENCE_ENGINE
  • DNN_BACKEND_OPENCV: 一般情况都是使用opencv dnn作为后台计算;
  • DNN_BACKEND_VKCOM
  • DNN_BACKEND_CUDA :使用GPU作为后台计算

设置目标设备

函数原型:

1
void cv::dnn::Net::setPreferableTarget  (int targetId);

参数为:

常见的目标设备如下:

  • DNN_TARGET_CPU:其中表示使用CPU计算,默认;
  • DNN_TARGET_OPENCL: 表示使用OpenCL加速,一般情况速度都很扯;
  • DNN_TARGET_OPENCL_FP16 :可以尝试;
  • DNN_TARGET_MYRIAD :树莓派上的;
  • DNN_TARGET_VULKAN
  • DNN_TARGET_FPGA :使用推理引擎的异构插件与CPU回退的FPGA设备;
  • DNN_TARGET_CUDA :在GPU上使用;
  • DNN_TARGET_CUDA_FP16

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//use opencv_dnn module for image classification by using GoogLeNet trained network
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <fstream>

using namespace cv;
using namespace cv::dnn;
using namespace std;

String modelTxt = "bvlc_googlenet.prototxt";
String modelBin = "bvlc_googlenet.caffemodel";
String labelFile = "classification_classes_ILSVRC2012.txt";

vector<String> readClasslabels();

int main(int argc, char** argv) {
Mat testImage = imread("dog.jpg");
if (testImage.empty()) {
printf("could not load image...\n");
return -1;
}
// create googlenet with caffemodel text and bin
Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
if (net.empty())
{
std::cerr << "Can't load network by using the following files: " << std::endl;
std::cerr << "prototxt: " << modelTxt << std::endl;
std::cerr << "caffemodel: " << modelBin << std::endl;
return -1;
}
net.setPreferableBackend(dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(dnn::DNN_TARGET_CPU);
// 读取分类数据
vector<String> labels = readClasslabels();
//GoogLeNet accepts only 224x224 RGB-images
Mat inputBlob = blobFromImage(testImage, 1, Size(224, 224), Scalar(104, 117, 123));//mean: Scalar(104, 117, 123)
// 支持1000个图像分类检测
Mat prob;
// 循环10+
for (int i = 0; i < 10; i++)
{
// 输入
net.setInput(inputBlob, "data");
// 分类预测
prob = net.forward("prob");
}
// 读取分类索引,最大与最小值
Mat probMat = prob.reshape(1, 1); //reshape the blob to 1x1000 matrix // 1000个分类
Point classNumber;
double classProb;
minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber); // 可能性最大的一个
int classIdx = classNumber.x; // 分类索引号
printf("\n current image classification : %s, possible : %.2f \n", labels.at(classIdx).c_str(), classProb);
putText(testImage, labels.at(classIdx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 255), 2, 8);
imshow("Image Category", testImage);
waitKey(0);
return 0;
}
/* 读取图像的1000个分类标记文本数据 */
vector<String> readClasslabels() {
std::vector<String> classNames;
std::ifstream fp(labelFile);
if (!fp.is_open())
{
std::cerr << "File with classes labels not found: " << labelFile << std::endl;
exit(-1);
}
std::string name;
while (!fp.eof())
{
std::getline(fp, name);
if (name.length())
classNames.push_back(name.substr(name.find(' ') + 1));
}
fp.close();
return classNames;
}

就是在上一篇的代码中添加了设置语句