OpenCV开发笔记(七十二):红胖子8分钟带你使用opencv+dnn+tensorFlow识别物体
前言
级联分类器的效果并不是很好,准确度相对深度学习较低,本章使用opencv通过tensorflow深度学习,检测已有模型的分类。
Demo


可以猜测,1其实是人,18序号类是狗,因为笔者未找到对应的分类具体信息。
Tensorflow模型下载
https://github.com/opencv/opencv_extra
(注意:未找到对应的分类具体信息。)
OpenCV深度识别基本流程
opencv3.4.x支持了各种模型。
支持的模型
opencv3.4.x支持一下深度学习的模型:
- caffe:.caffemodel
官网:http://caffe.berkeleyvision.org
- tensorflow:.pb
官网:https://www.tensorflow.org
- torch:.t7 | .net
官网:http://torch.ch
- darknet:.weights
官网:https://pjreddie.com/darknet
- DLDT:.bin
官网:https://software.intel.com/openvino-toolkit
操作步骤:tensorflow
- 步骤一:加载模型和配置文件,建立神经网络。
根据不同的模型,使用cv::dnn::readNetFromXXX系列函数进行读取,opencv3.4.x系列支持的dnn模型(支持模型往上看)。
举例tensorflow模型如下:
std::string weights = "E:/qtProject/openCVDemo/dnnData/" \
"ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb";
std::string prototxt = "E:/qtProject/openCVDemo/dnnData/" \
"ssd_mobilenet_v1_coco_2017_11_17.pbtxt";
cv::dnn::Net net = cv::dnn::readNetFromTensorflow(weights, prototxt);
- 步骤二:将要预测的图片加入到神经网络中
加入之后,需要识别图片,那么需要把图片输入到神经网络当中去,如下:
cv::Mat mat;
cv::Mat blob;
mat = cv::imread("E:/testFile/14.jpg");
cv::dnn::blobFromImage(mat, blob);
- 步骤三:分类预测,获取识别的结果
输入之后,就进行识别,识别是向前预测(分类预测),并且拿到结果。
cv::Mat prob = net.forward();
对于预测的结果,存于cv::Mat类型的prob,然后需要统一对prob进行处理,使其成为我们可以使用的数据,代码如下:
cv::Mat detectionMat(prob.size[2], prob.size[3], CV_32F, prob.ptr<float>());
对于从结果prob转换为detectionMat后,其结构如下:
cv::Mat为多行七列,每一行代表一个检测到的分类,具体列信息如下表:

(注意:具体的使用,请参照“步骤四”)
- 步骤四:对达到置信度的可以通过输出的mat进行分类和框选
cv::Mat detectionMat(prob.size[2], prob.size[3], CV_32F, prob.ptr<float>());
// 置信度预制,大于执行度的将其使用rect框出来
float confidenceThreshold = 0.75;
for(int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at<float>(i, 2);
if (confidence > confidenceThreshold)
{
// 高于置信度的,获取其x、y、以及对应的宽度高度,进行框选
int classId = (detectionMat.at<float>(i, 1));
int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * mat.cols);
int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * mat.rows);
int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * mat.cols);
int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * mat.rows);
cv::Rect object((int)xLeftBottom,
(int)yLeftBottom,
(int)(xRightTop - xLeftBottom),
(int)(yRightTop - yLeftBottom));
cv::rectangle(mat, object, cv::Scalar(0, 255, 0), 2);
qDebug() << __FILE__ << __LINE__
<< classId
<< confidence << confidenceThreshold
<< object.x << object.y << object.width << object.height;
}
}
函数原型
读取tensorflow模型与配置文件函数原型
Net readNetFromTensorflow(const String &model,
const String &config = String());
从文件中读取。
- 参数一:用二进制协议描述网络体系结构的.pb文件的路径;
- 参数二:包含protobuf格式的文本图形定义的.pbtxt文件的路径。生成的网络对象由文本图构建,使用来自二进制的权重让我们更灵活些;
Net readNetFromTensorflow(const std::vector<uchar>& bufferModel,
const std::vector<uchar>& bufferConfig = std::vector<uchar>());
从缓存中读取。
- 参数一:包含pb文件内容的bufferModel缓冲区;
- 参数二:包含pbtxt文件内容的bufferConfig缓冲区;
Net readNetFromTensorflow(const char *bufferModel,
size_t lenModel,
const char *bufferConfig = NULL,
size_t lenConfig = 0);
- 参数一:包含pb文件内容的bufferModel缓冲区;
- 参数二:bufferModel缓冲长度;
- 参数三:包含pbtxt文件内容的bufferConfig缓冲区;
- 参数四:bufferConfig缓冲长度;
读取图片(需要识别的)函数原型
Mat blobFromImage(InputArray image,
double scalefactor=1.0,
const Size& size = Size(),
const Scalar& mean = Scalar(),
bool swapRB=false,
bool crop=false,
int ddepth=CV_32F);
void blobFromImage(InputArray image,
OutputArray blob,
double scalefactor=1.0,
const Size& size = Size(),
const Scalar& mean = Scalar(),
bool swapRB=false,
bool crop=false,
int ddepth=CV_32F);.
Mat blobFromImages(InputArrayOfArrays images,
double scalefactor=1.0,
Size size = Size(),
const Scalar& mean = Scalar(),
bool swapRB=false,
bool crop=false,
int ddepth=CV_32F);
void blobFromImages(InputArrayOfArrays images,
OutputArray blob,
double scalefactor=1.0,
Size size = Size(),
const Scalar& mean = Scalar(),
bool swapRB=false,
bool crop=false,
int ddepth=CV_32F);
从图像创建区域。可选择从中心调整和裁剪图像。
- 参数一:图像输入图像(1、3或4通道);
- 参数二:大小输出图像的空间大小;
- 参数三:从通道中减去平均值的平均标量。价值是有意的,如果image有BGR顺序,swapRB为真,则按(mean-R,mean-G,mean-B)顺序排列;
- 参数四:图像值的缩放因子乘数;
- 参数五:swapRB标志,指示交换第一个和最后一个通道,在三通道图像是必要的;
- 参数六:裁剪标志,指示调整大小后是否裁剪图像;
- 参数七:输出blob的深度,选择CV_32F或CV_8U;
设置神经网络输入函数原型
void cv::dnn::Net::setInput(InputArray blob,
const String& name = "",
double scalefactor = 1.0,
const Scalar& mean = Scalar());
设置网络的新输入值。
- 参数一:一个新的blob。应具有CV_32F或CV_8U深度。
- 参数二:输入层的名称。
- 参数三:可选的标准化刻度。
- 参数四:可选的平均减去值。
深度检测识别(向前预测)函数原型
void cv::dnn::Net::Mat forward(const String& outputName = String());
向前预测,返回指定层的第一个输出的blob,一般是返回最后一层,可使用cv::Net::getLayarNames()获取所有的层名称。
- 参数一:outputName需要获取输出的层的名称
Demo源码
void OpenCVManager::testTensorflow()
{
// 训练好的模型以及其模型的后缀名
// .caffemodel (Caffe, http://caffe.berkeleyvision.org/)
// .pb (TensorFlow, https://www.tensorflow.org/)
// .t7 | *.net (Torch, http://torch.ch/)
// .weights (Darknet, https://pjreddie.com/darknet/)
// .bin (DLDT, https://software.intel.com/openvino-toolkit)
// https://github.com/opencv/opencv/wiki/TensorFlow-Object-Detection-API
std::string weights = "E:/qtProject/openCVDemo/dnnData/" \
"ssd_mobilenet_v1_coco_2017_11_17/"frozen_inference_graph.pb";
std::string prototxt = "E:/qtProject/openCVDemo/dnnData/" \
"ssd_mobilenet_v1_coco_2017_11_17.pbtxt";
cv::dnn::Net net = cv::dnn::readNetFromTensorflow(weights, prototxt);
if(net.empty())
{
qDebug() << __FILE__ << __LINE__ << "net is empty!!!";
return;
}
cv::Mat mat;
cv::Mat blob;
// 获得所有层的名称和索引
std::vector<cv::String> layerNames = net.getLayerNames();
int lastLayerId = net.getLayerId(layerNames[layerNames.size() - 1]);
cv::Ptr<cv::dnn::Layer> lastLayer = net.getLayer(cv::dnn::DictValue(lastLayerId));
qDebug() << __FILE__ << __LINE__
<< QString(lastLayer->type.c_str())
<< QString(lastLayer->getDefaultName().c_str())
<< QString(layerNames[layerNames.size()-1].c_str());
#if 0
// 视频里面的识别
cv::VideoCapture capture;
if(!capture.open("E:/testFile/4.avi"))
{
qDebug() << __FILE__ << __LINE__ << "Failed to open videofile!!!";
return;
}
#endif
while(true)
{
#if 1
// 读取图片识别
mat = cv::imread("E:/testFile/15.jpg");
if(!mat.data)
{
qDebug() << __FILE__ << __LINE__ << "Failed to read image!!!";
return;
}
#else
// 视频里面的识别
capture >> mat;
if(mat.empty())
{
cv::waitKey(0);
break;
}
#endif
cv::dnn::blobFromImage(mat, blob);
net.setInput(blob);
// 推理预测:可以输入预测的图层名称
// cv::Mat prob = net.forward("detection_out");
cv::Mat prob = net.forward();
// 显示识别花费的时间
std::vector<double> layersTimes;
double freq = cv::getTickFrequency() / 1000;
double t = net.getPerfProfile(layersTimes) / freq;
std::string label = cv::format("Inference time: %.2f ms", t);
cv::putText(mat, label, cv::Point(0, 15), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0));
cv::Mat detectionMat(prob.size[2], prob.size[3], CV_32F, prob.ptr<float>());
// 置信度预制,大于执行度的将其使用rect框出来
float confidenceThreshold = 0.75;
for(int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at<float>(i, 2);
if (confidence > confidenceThreshold)
{
// 高于置信度的,获取其x、y、以及对应的宽度高度,进行框选
int classId = (detectionMat.at<float>(i, 1));
int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * mat.cols);
int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * mat.rows);
int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * mat.cols);
int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * mat.rows);
cv::Rect object((int)xLeftBottom,
(int)yLeftBottom,
(int)(xRightTop - xLeftBottom),
(int)(yRightTop - yLeftBottom));
cv::rectangle(mat, object, cv::Scalar(0, 255, 0), 2);
qDebug() << __FILE__ << __LINE__
<< classId
<< confidence << confidenceThreshold
<< object.x << object.y << object.width << object.height;
}
}
cv::imshow(_windowTitle.toStdString(), mat);
cv::waitKey(0);
}
}
对应工程模板v1.64.0
openCVDemo_v1.64.0_基础模板_tensorFlow分类检测.rar。
入坑
入坑一:加载模型时候错误
错误

原因
.pb模型文件与.pbtxt文件不对应,版本也有关系。
解决
更换模型,使用正确的pb与pbtxt对应的文件。
上一篇:《OpenCV开发笔记(七十一):红胖子8分钟带你深入级联分类器训练》
下一篇:持续补充中…
OpenCV开发笔记(七十二):红胖子8分钟带你使用opencv+dnn+tensorFlow识别物体的更多相关文章
- OpenCV开发笔记(七十三):红胖子8分钟带你使用opencv+dnn+yolov3识别物体
前言 级联分类器的效果并不是很好,准确度相对深度学习较低,上一章节使用了dnn中的tensorflow,本章使用yolov3模型,识别出具体的分类. Demo 320x320,置信度0 ...
- OpenCV开发笔记(六十五):红胖子8分钟带你深入了解ORB特征点(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- OpenCV开发笔记(六十九):红胖子8分钟带你使用传统方法识别已知物体(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- OpenCV开发笔记(五十六):红胖子8分钟带你深入了解多种图形拟合逼近轮廓(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- OpenCV开发笔记(六十四):红胖子8分钟带你深入了解SURF特征点(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- OpenCV开发笔记(七十一):红胖子8分钟带你深入级联分类器训练
前言 红胖子,来也! 做图像处理,经常头痛的是明明分离出来了(非颜色的),分为几块区域,那怎么知道这几块区域到底哪一块是我们需要的,那么这部分就涉及到需要识别了. 识别可以自己写模板匹配.特征 ...
- OpenCV开发笔记(五十五):红胖子8分钟带你深入了解Haar、LBP特征以及级联分类器识别过程(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- 树莓派开发笔记(十二):入手研华ADVANTECH工控树莓派UNO-220套件(一):介绍和运行系统
前言 树莓派也可以做商业应用,工业控制,其稳定性和可靠性已经得到了验证,故而工业控制,一些停车场等场景也有采用树莓派作为主控的,本片介绍了研华ADVANTECH的树莓派套件组UNO-220-P4N ...
- .net开发笔记(十二) 设计时与运行时的区别(续)
上一篇博客详细讲到了设计时(DesignTime)和运行时(RunTime)的概念与区别,不过没有给出实际的Demo,今天整理了一下,做了一个例子,贴出来分享一下,巩固前一篇博客讲到的内容. 简单回顾 ...
随机推荐
- java事件触发
工作遇到一个问题:用netty实现服务和设备的交互,服务发送了一组指令,需要再等待时间内获取结果,如果结果提前全部返回,就进一步处理,如果等待时间内没有全部返回,就视为失败处理. 这个场景我遇到的困难 ...
- Do not use built-in or reserved HTML elements as component id:mask vue报错
今天学习了一下vue的组件,但是报了一个错误 Do not use built-in or reserved HTML elements as component id:mask , 经过查询得知是因 ...
- windows服务器添加磁盘后,提示The disk is offline because of policy set by an administrator的解决办法
操作系统:Windows Server 2008 R2 Enterprise 事件:存储在虚拟机上添加三块磁盘,笔者准备扩展到E盘(动态分区) 问题:存储团队添加磁盘后,OS的磁盘管理界面,看到提示, ...
- 大白话谈JVM的类加载机制
前言 我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢. 如果懂得了JVM的运行原理和内存模型,像是一些JVM调优.垃圾回收机制等等的问题我们才 ...
- spark textfile rdd 日记
批量处理模板方法, 核心处理方法为内部方法 def batchProces(sc: SparkContext, locationFlag: Int, minid: Int, maxid: Int, n ...
- 018 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 12 数据类型转换的基本概念
018 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 12 数据类型转换的基本概念 本文知识点:Java中的数据类型转换 类型转换 类型转换分类 2类,分别是: ...
- matlab中fspecial Create predefined 2-D filter以及中值滤波均值滤波以及高斯滤波
来源: 1.https://ww2.mathworks.cn/help/images/ref/fspecial.html?searchHighlight=fspecial&s_tid=doc_ ...
- matlab中ceil朝正无穷大四舍五入
来源:https://ww2.mathworks.cn/help/matlab/ref/ceil.html?searchHighlight=ceil&s_tid=doc_srchtitle 本 ...
- Nginx(五)、http反向代理的实现
上一篇nginx的文章中,我们理解了整个http正向代理的运行流程原理,主要就是事件机制接入,header解析,body解析,然后遍历各种checker,以及详细讲解了其正向代理的具体实现过程.这已经 ...
- Hadoop理论基础
Hadoop是 Apache 旗下的一个用 java 语言实现开源软件框架,是一个开发和运行处理大规模数据的软件平台.允许使用简单的编程模型在大量计算机集群上对大型数据集进行分布式处理. 特性:扩 ...