Table of Contents
下载所需档案
配置
第一步:OpenCV配置
第二步:错误: E1696 無法開啟 來源 檔案 "common.hpp"
第三步:错误:C4996 'getenv': This function or variable may be unsafe.
控制台参数
代码
效果图
参考文章
https://docs.opencv.org/master/d5/de7/tutorial_dnn_googlenet.html
Firstly, download GoogLeNet model files: bvlc_googlenet.prototxt and bvlc_googlenet.caffemodel
Also you need file with names of ILSVRC2012 classes: classification_classes_ILSVRC2012.txt.
Put these files into working dir of this program example.
笔者翻译:
首先,下载GoogLeNet模型文件:bvlc_googlenet.prototxt和 bvlc_googlenet.caffemodel
还需要带有这个名字“ILSVRC2012”的分类文件 classification_classes_ILSVRC2012.txt
把这些文件放至程序的工作目录中。
我把它们都放置在E:/template文件夹下了,个人习惯
档案名称 | 下载地址 | 大小(KB) |
bvlc_googlenet.prototxt | https://github.com/opencv/opencv_extra/blob/master/testdata/ dnn/bvlc_googlenet.prototxt |
38 |
bvlc_googlenet.caffemodel | http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel | 52,280 |
classification_classes_ILSVRC2012.txt | https://github.com/opencv/opencv/blob/master/samples/ data/dnn/classification_classes_ILSVRC2012.txt |
23 |
请仔细看文章《OpenCV4.1 DNN Sample C++配置 VS2017 + Windows》
解决办法:
由于需要使用common.hpp文件,所以需要引入dnn目录到include中
我电脑上的路径为“D:\OpenCV\opencv410\sources\samples\dnn”
C4996 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
解决办法:在C/C++ ->预处理中添加“_CRT_SECURE_NO_WARNINGS”即可
--model=e:/template/bvlc_googlenet.caffemodel --config=e:/template/bvlc_googlenet.prototxt --width=224 --height=224 --classes=e:/template/classification_classes_ILSVRC2012.txt --mean="104 117 123" --rgb --input=E:/template/images/dog1.jpg
也可以在控制台(cmd)中运行,如下图:
classification.exe --model=e:/template/bvlc_googlenet.caffemodel --config=e:/template/bvlc_googlenet.prototxt --width=224 --height=224 --classes=e:/template/classification_classes_ILSVRC2012.txt --mean="104 117 123" --rgb --input=E:/template/images/dog1.jpg
【注意】我把“--input=E:/template/images/cat1.jpg”放在了最后,因为方便修改图片名字
【注意】:从网页上直接复制这些参数可能会报下面的错误,我就遇到了,空格变成问号……
Error: Requested object was not found
解决办法:
把它们在Notepad++中正常写一遍再填入即可,每个“--”前是一个空格。
OpenCV官网也有的,链接如下:
https://docs.opencv.org/master/d5/de7/tutorial_dnn_googlenet.html
注意事项:
1. 我的代码多了这行#include "pch.h",我是用Visual Studio建立的带有预编译头的项目,不是空项目
2. #include "common.hpp"
这里面就三个函数,如下
我电脑上的路径为“D:\OpenCV\opencv410\sources\samples\dnn”
std::string genArgument(const std::string& argName, const std::string& help,
const std::string& modelName, const std::string& zooFile,
char key = ' ', std::string defaultVal = "");
std::string genPreprocArguments(const std::string& modelName, const std::string& zooFile);
std::string findFile(const std::string& filename);
3. 关于CommandLineParser,不会用的请参考这篇文章【强烈推荐的,这样更改图片时不用每次都重新build】
《OpenCV3 CommandLineParser类代码实例 使用说明 播放视频及效果图 VS2013控制台程序带参数的设定方法》
完整代码如下:
#include "pch.h"
#include
#include
#include
#include
#include
#include "common.hpp"
//控制台参数
std::string keys =
"{ help h | | Print help message. }"
"{ @alias | | An alias name of model to extract preprocessing parameters from models.yml file. }"
"{ zoo | models.yml | An optional path to file with preprocessing parameters }"
"{ input i | | Path to input image or video file. Skip this argument to capture frames from a camera.}"
"{ framework f | | Optional name of an origin framework of the model. Detect it automatically if it does not set. }"
"{ classes | | Optional path to a text file with names of classes. }"
"{ backend | 0 | Choose one of computation backends: "
"0: automatically (by default), "
"1: Halide language (http://halide-lang.org/), "
"2: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
"3: OpenCV implementation }"
"{ target | 0 | Choose one of target computation devices: "
"0: CPU target (by default), "
"1: OpenCL, "
"2: OpenCL fp16 (half-float precision), "
"3: VPU }";
using namespace cv;
using namespace dnn;
std::vector classes;
int main(int argc, char** argv)
{
CommandLineParser parser(argc, argv, keys);
const std::string modelName = parser.get("@alias");
const std::string zooFile = parser.get("zoo");
keys += genPreprocArguments(modelName, zooFile);
parser = CommandLineParser(argc, argv, keys);
parser.about("Use this script to run classification deep learning networks using OpenCV.");
if (argc == 1 || parser.has("help"))
{
parser.printMessage();
return 0;
}
float scale = parser.get("scale");
Scalar mean = parser.get("mean");
bool swapRB = parser.get("rgb");
int inpWidth = parser.get("width");
int inpHeight = parser.get("height");
String model = findFile(parser.get("model"));
String config = findFile(parser.get("config"));
String framework = parser.get("framework");
int backendId = parser.get("backend");
int targetId = parser.get("target");
// Open file with classes names.打开文件
if (parser.has("classes"))
{
std::string file = parser.get("classes");
std::ifstream ifs(file.c_str());
if (!ifs.is_open())
CV_Error(Error::StsError, "File " + file + " not found");
std::string line;
while (std::getline(ifs, line))
{
classes.push_back(line);
}
}
if (!parser.check())
{
parser.printErrors();
return 1;
}
CV_Assert(!model.empty());
Net net = readNet(model, config, framework);
net.setPreferableBackend(backendId);
net.setPreferableTarget(targetId);
// Create a window创建一个窗口
static const std::string kWinName = "Deep learning image classification in OpenCV";
namedWindow(kWinName, WINDOW_NORMAL);
//如果参数中有--input,就打开输入的图片,否则就打开摄像头
VideoCapture cap;
if (parser.has("input"))
cap.open(parser.get("input"));
else
cap.open(0);
// Process frames.
Mat frame, blob;
while (waitKey(1) < 0)
{
cap >> frame;
if (frame.empty())
{
waitKey();
break;
}
blobFromImage(frame, blob, scale, Size(inpWidth, inpHeight), mean, swapRB, false);
net.setInput(blob);
Mat prob = net.forward();
Point classIdPoint;
double confidence;
minMaxLoc(prob.reshape(1, 1), 0, &confidence, 0, &classIdPoint);
int classId = classIdPoint.x;
// Put efficiency information.
std::vector layersTimes;
double freq = getTickFrequency() / 1000;
double t = net.getPerfProfile(layersTimes) / freq;
std::string label = format("Inference time: %.2f ms", t);
putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
// Print predicted class.
label = format("%s: %.4f", (classes.empty() ? format("Class #%d", classId).c_str() :
classes[classId].c_str()),
confidence);
putText(frame, label, Point(0, 40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
imshow(kWinName, frame);
}
return 0;
}
图片是从百度上搜的
识别结果有的正确,有的错误。
识别结果的准确率是依赖模型的,接下来我们可以考虑根据特定的情况、条件来训练特定模型。
以下识别所用时间不长,是因为我使用的Release版,Debug版时间会稍微久一些。
下面这张是官网图片,准确率还是很高的
我还特地找了一些漫画性质的猫,结果大家自己看吧
Pizza识别成golf ball~~