介绍
在本教程中,您将学习如何使用来自 Caffe 模型库的 GoogLeNet 训练网络opencv_dnn模块进行图像分类。
我们将在下图中演示此示例的结果。
源代码
我们将使用示例应用程序中的片段,可以在此处下载。
#include < fstream>
#include < sstream>
#include < iostream>
#include < opencv2/dnn.hpp>
#include < opencv2/imgproc.hpp>
#include < opencv2/highgui.hpp>
#include“common.hpp”
std::string 键 =
“{ 帮助 h | |打印帮助消息。}"
“{ @alias | |用于从 models.yml 文件中提取预处理参数的模型别名。}"
“{ 动物园 |模型.yml |带有预处理参数的文件的可选路径 }”
“{ 输入 i | |输入图像或视频文件的路径。跳过此参数以从相机捕获帧。
“{ initial_width |0 |通过初始调整大小到特定宽度来预处理输入图像。
“{ initial_height |0 |通过初始调整大小到特定高度来预处理输入图像。
“{ std |0.0 0.0 0.0 |通过除以标准差对输入图像进行预处理。
“{ 裁剪 |假 |通过中心裁剪对输入图像进行预处理。
“{ 框架 f | |模型的原始框架的可选名称。如果未设置,则自动检测它。}"
“{ 需要Softmax |假 |使用 Softmax 对网络的输出进行后处理。
“{ 类 | |包含类名称的文本文件的可选路径。}"
“{ 后端 |0 |选择计算后端之一:”
“0:自动(默认),”
“1:卤化物语(http://halide-lang.org/), ”
“2:英特尔的深度学习推理引擎(https://software.intel.com/openvino-toolkit),
“3:OpenCV的实现,”
“4:VKCOM,”
“5:CUDA,”
“6:WebNN }”
“{ 目标 |0 |选择目标计算设备之一:”
“0:CPU 目标(默认)、”
“1:OpenCL,”
“2:OpenCL fp16(半浮点精度), ”
“3:VPU,”
“4:Vulkan,”
“6:CUDA,”
“7:CUDA fp16(半浮点预处理)}”;
使用命名空间 CV;
使用命名空间 DNN;
std::vector<std::string> 类;
int main(int argc, char** argv)
{
CommandLineParser 解析器(argc, argv, keys);
const std::string modelName = parser.get<String>(“@alias”);
const std::string zooFile = parser.get<String>(“zoo”);
键 += genPreprocArguments(modelName, zooFile);
解析器 = CommandLineParser(argc, argv, keys);
parser.about(“使用此脚本使用 OpenCV 运行分类深度学习网络。);
if (argc == 1 || parser.has(“帮助”))
{
解析器.printMessage();
返回 0;
}
int rszWidth = 解析器.get<int>(“initial_width”);
int rszHeight = 解析器.get<int>(“initial_height”);
浮点比例 = parser.get<float>(“scale”);
标量均值 = parser.get<Scalar>(“mean”);
标量标准 = parser.get<标量>(“标准”);
布尔交换RB = 解析器.get<布尔>(“rgb”);
bool 裁剪 = parser.get<bool>(“crop”);
int inpWidth = 解析器.get<int>(“宽度”);
int inpHeight = 解析器.get<int>(“高度”);
字符串模型 = findFile(parser.get<String>(“model”));
字符串配置 = findFile(parser.get<String>(“config”));
字符串框架 = parser.get<String>(“framework”);
int backendId = parser.get<int>(“后端”);
int targetId = 解析器.get<int>(“目标”);
bool needSoftmax = 解析器.get<bool>(“needSoftmax”);
std::cout<<“mean: ”<<mean<<std::endl;
std::cout<<“std: ”<<std<<std::endl;
打开带有类名称的文件。
if (parser.has(“类”))
{
std::string 文件 = parser.get<String>(“类”);
标准::ifstream ifs(file.c_str());
如果 (!ifs.is_open())
CV_Error(错误::StsError,“文件”+文件+“未找到”);
std::string 行;
而 (std::getline(ifs, line))
{
classes.push_back(线);
}
}
如果 (!parser.check())
{
解析器.printErrors();
返回 1;
}
CV_Assert(!model.empty());
Net net = readNet(model, config, framework);
net.setPreferableBackend(backendId);
net.setPreferableTarget(目标Id);
创建窗口
static const std::string kWinName = “OpenCV中的深度学习图像分类”;
namedWindow (kWinName, WINDOW_NORMAL);
VideoCapture 帽;
if (parser.has(“输入”))
帽。open(parser.get<String>(“输入”));
还
帽。打开(0);
处理帧。
垫框,斑点;
而 (waitKey(1) < 0)
{
帽>>框架;
如果 (frame.empty())
{
等待键();
破;
}
if (rszWidth != 0 && rszHeight != 0)
{
resize(frame, frame, Size(rszWidth, rszHeight));
}
blobFromImage(frame, blob, scale, Size(inpWidth, inpHeight), mean, swapRB, crop);
检查 std 值。
if (std.val[0] != 0.0 && std.val[1] != 0.0 && std.val[2] != 0.0)
{
将 blob 除以 std。
除法(blob, std, blob);
}
net.setInput(blob);
双t_sum = 0.0;
双T;
int 类 Id;
双重置信度;
cv::TickMeter 时间记录器;
timeRecorder。重置();
垫子概率 = net.forward();
双T1;
timeRecorder。开始();
prob = net.forward();
timeRecorder。停();
t1 = 时间记录器。getTimeMilli();
timeRecorder。重置();
for(int i = 0; i < 200; i++) {
timeRecorder。开始();
prob = net.forward();
timeRecorder。停();
点类IdPoint;
minMaxLoc(prob.reshape(1, 1), 0, &confidence, 0, &classIdPoint);
classId = classIdPoint。倍;
放置效率信息。
std::vector<double> layersTimes;
double freq = getTickFrequency() / 1000;
t = net.getPerfProfile(layersTimes) / freq;
t_sum += 吨;
}
如果 (needSoftmax == true)
{
浮点数 maxProb = 0.0;
浮点和 = 0.0;
垫子 softmaxProb;
maxProb = *std::max_element(prob.begin<float>(), prob.end<float>());
cv::exp(prob-maxProb, softmaxProb);
sum = (float)cv::sum(softmaxProb)[0];
softmaxProb /= 总和;
点类IdPoint;
minMaxLoc(softmaxProb.reshape(1, 1), 0, &confidence, 0, &classIdPoint);
classId = classIdPoint。倍;
}
std::string label = format(“1轮推理时间:%.2f ms”, t1);
std::string label2 = format(“200 轮的平均时间:%.2f ms”, timeRecorder.getTimeMilli()/200);
putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
putText(frame, label2, Point(0, 35), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
打印预测的类。
label = format(“%s: %.4f”, (classes.empty() ?format(“类 #%d”, classId).c_str() :
类[classId].c_str()),
信心);
putText(frame, label, Point(0, 55), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
imshow(kWinName, 帧);
}
返回 0;
}
解释
-
首先,下载GoogLeNet模型文件:bvlc_googlenet.prototxt和bvlc_googlenet.caffemodel
此外,您还需要包含ILSVRC2012类名称的文件:classification_classes_ILSVRC2012.txt。
将这些文件放入此程序示例的工作目录中。
- 使用 .prototxt 和 .caffemodel 文件的路径读取和初始化网络 Net net = readNet(model, config, framework);net.setPreferableBackend(backendId);net.setPreferableTarget(目标Id);
framework
model
config
.caffemodel
.prototxt
-
读取输入图像并转换为 blob,GoogleNet 可接受
VideoCapture 帽;if (parser.has(“输入”))帽。open(parser.get<String>(“输入”));还cap.open(0);cv::VideoCapture 可以加载图像和视频。
bIobfromimage(frame, blob, scale, Size(inpWidth, inpHeight), mean, swapRB, crop);检查 std 值。if (std.val[0] != 0.0 && std.val[1] != 0.0 && std.val[2] != 0.0){将 blob 除以 std。除法(blob, std, blob);}在使用 cv::d nn::blobFromImage 函数对每个蓝色、绿色和红色通道进行必要的预处理(如调整大小和均值减法)后,我们将图像转换为具有形状的 4 维斑点(所谓的批处理)。
1x3x224x224
(-104, -117, -123)
- 将 blob 传递到网络 net.setInput(blob);
- 向前传球 双t_sum = 0.0;双T;int 类 Id;双重置信度;cv::TickMeter 时间记录器;timeRecorder。重置();垫子概率 = net.forward();双T1;timeRecorder。开始();prob = net.forward();timeRecorder。停();t1 = 时间记录器。getTimeMilli();timeRecorder。重置();for(int i = 0; i < 200; i++) {
- 确定最佳班级 点类IdPoint;minMaxLoc(prob.reshape(1, 1), 0, &confidence, 0, &classIdPoint);classId = classIdPoint.x;
prob
- 从命令行运行示例 ./example_dnn_classification --model=bvlc_googlenet.caffemodel --config=bvlc_googlenet.prototxt --width=224 --height=224 --classes=classification_classes_ILSVRC2012.txt --input=space_shuttle.jpg --mean=“104 117 123”
space shuttle
在线教程
- 麻省理工学院人工智能视频教程 – 麻省理工人工智能课程
- 人工智能入门 – 人工智能基础学习。Peter Norvig举办的课程
- EdX 人工智能 – 此课程讲授人工智能计算机系统设计的基本概念和技术。
- 人工智能中的计划 – 计划是人工智能系统的基础部分之一。在这个课程中,你将会学习到让机器人执行一系列动作所需要的基本算法。
- 机器人人工智能 – 这个课程将会教授你实现人工智能的基本方法,包括:概率推算,计划和搜索,本地化,跟踪和控制,全部都是围绕有关机器人设计。
- 机器学习 – 有指导和无指导情况下的基本机器学习算法
- 机器学习中的神经网络 – 智能神经网络上的算法和实践经验
- 斯坦福统计学习
有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
人工智能书籍
- OpenCV(中文版).(布拉德斯基等)
- OpenCV+3计算机视觉++Python语言实现+第二版
- OpenCV3编程入门 毛星云编著
- 数字图像处理_第三版
- 人工智能:一种现代的方法
- 深度学习面试宝典
- 深度学习之PyTorch物体检测实战
- 吴恩达DeepLearning.ai中文版笔记
- 计算机视觉中的多视图几何
- PyTorch-官方推荐教程-英文版
- 《神经网络与深度学习》(邱锡鹏-20191121)
- …
第一阶段:零基础入门(3-6个月)
新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。
第二阶段:基础进阶(3-6个月)
熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。
第三阶段:工作应用
这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。
有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓