1,模块介绍
OpenCV中的深度学习模块(DNN)只提供了推理功能,不涉及模型的训练,支持多种深度学习框架,比如TensorFlow,Caffe,Torch和Darknet。
轻量型。DNN模块只实现了推理功能,代码量及编译运行开销远小于其他深度学习模型框架。
使用方便。DNN模块提供了内建的CPU和GPU加速,无需依赖第三方库,若项目中之前使用了OpenCV,那么通过DNN模块可以很方便的为原项目添加深度学习的能力。
通用性。DNN模块支持多种网络模型格式,用户无需额外的进行网络模型的转换就可以直接使用,支持的网络结构涵盖了常用的目标分类,目标检测和图像分割的类别
2,OpenCV DNN 中支持的模型
3,OpenCV DNN 中支持的功能
图像分类、对象检测、图像分割、场景文字检测、人脸检测与识别
4,接口用法
4.1加载一个DNN网络 ,API:readNet、readNetFromCaffe、readNetFromTensorflow等等从不同的模块加载网络
//以caffemodel为例
CV_EXPORTS_W Net readNetFromCaffe(const String &prototxt, const String &caffeModel = String());
加载网络
#include<opencv2/opencv.hpp>
#include<opencv2/dnn.hpp>//包含DNN模块头文件
#include<iostream>
using namespace std;
using namespace cv;
using namespace cv::dnn;
//以bvlc_googlenet.caffemodel为例
string bin_model = "F:/code/opencv_tutorial/data/models/googlenet/bvlc_googlenet.caffemodel";//模型的权重文件
string protxt = "F:/code/opencv_tutorial/data/models/googlenet/bvlc_googlenet.prototxt";//模型的描述文件
//Load DNN model
Net net = readNetFromCaffe(protxt, bin_model);
4.2获取各个层的信息
//获取各层信息
vector<string> layer_names = net.getLayerNames();
cout << "layer id :" <<" "<< "layer type:" << " " << "layer name:" << endl;
for (int i = 0; i < layer_names.size(); i++) {
int id = net.getLayerId(layer_names[i]);
auto layer = net.getLayer(id);
cout << id << " " << layer->type.c_str() << " " << layer->name.c_str() << endl;
}
4.3设置计算后台与支持设备
//设置计算后台
net.setPreferableBackend(DNN_BACKEND_OPENCV);
//设置支持设备
net.setPreferableTarget(DNN_TARGET_CPU);
4.4设置输入
dnn.blobFromImage
作用:根据输入图像,创建维度N(图片的个数),通道数C,高H和宽W次序的blobs。
blobFromImage(image,
scalefactor=None,
size=None,
mean=None,
swapRB=None,
crop=None,
ddepth=None):
参数:
image:cv2.imread 读取的图片数据
scalefactor: 缩放像素值,如 [0, 255] – [0, 1]
size: 输出blob(图像)的尺寸,如 (netInWidth, netInHeight)
mean: 从各通道减均值. 如果输入 image 为 BGR 次序,且swapRB=True,则通道次序为 (mean-R, mean-G, mean-B).
swapRB: 交换 3 通道图片的第一个和最后一个通道,如 BGR – RGB
crop: 图像尺寸 resize 后是否裁剪. 如果crop=True,则,输入图片的尺寸调整resize后,一个边对应与 size 的一个维度,而另一个边的值大于等于 size 的另一个维度;然后从 resize 后的图片中心进行 crop. 如果crop=False,则无需 crop,只需保持图片的长宽比
ddepth: 输出 blob 的 Depth. 可选: CV_32F 或 CV_8U
示例:
img_cv2 = cv2.imread("test.jpeg")
inWidth = 256
inHeight = 256
cv::Mat blob = cv2.dnn.blobFromImage(img_cv2,
scalefactor=1.0 / 255,
size=(inWidth, inHeight),
mean=(0, 0, 0),
swapRB=False,
crop=False)
4.5设置网络模型输入:
net.setInput(blob);
output = net.forward();
4.6执行网络推理并得到输出结果:
out=net.forward()
5,完整代码示例
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
using namespace cv::dnn;
String model_bin_file = "model/bvlc_googlenet.caffemodel";
String model_txt_file = "model/bvlc_googlenet.prototxt";
String labels_txt_file = "model/synset_words.txt";
vector<String> readLabels();
int main(int argc, char** argv)
{
Mat src = imread("pictures/girl.jpg");
if (src.empty())
{
cout << "could not open image……" << endl;
return -1;
}
namedWindow("src", WINDOW_FREERATIO);
imshow("src", src);
// 读取labels
vector<String> labels = readLabels();
// 读取网络 包括模型描述文件和和模型文件
Net net = readNetFromCaffe(model_txt_file, model_bin_file);
if (net.empty())
{
cout << "net could not load……" << endl;
return -1;
}
Mat inputBlob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123));
Mat prob;
for (size_t i = 0; i < 10; i++)
{
net.setInput(inputBlob, "data");
prob = net.forward("prob"); // 输出为1×1000 1000类的概率
}
Mat proMat = prob.reshape(1, 1); // 单通道 一行
Point classNumber;
double classProb;
minMaxLoc(proMat, NULL, &classProb, NULL, &classNumber);
int classidx = classNumber.x;
cout << "current image classification:" << labels.at(classidx).c_str()
<< "possible:" << classProb << endl;
putText(src, labels.at(classidx), Point(20, 20), FONT_HERSHEY_PLAIN, 1.5, Scalar(0, 0, 255), 1, 8);
imshow("image", src);
waitKey(0);
return 0;
}
vector<String> readLabels()
{
vector<String> classNames;
ifstream fin(labels_txt_file.c_str());
if (!fin.is_open())
{
cout << "could not open the file……" << endl;
exit(-1);
}
string name;
while (!fin.eof())
{
getline(fin, name);
if (name.length())
{
classNames.push_back(name.substr(name.find(" " + 1)));// 按空格的位置往后移一位进行分割
}
}
fin.close();
return classNames;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/182004.html