若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/109201809
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

OpenCV开发专栏(点击传送门)

上一篇:《OpenCV开发笔记(七十二):红胖子8分钟带你使用opencv+dnn+tensorFlow识别物体》
下一篇:持续补充中…

前言

级联分类器的效果并不是很好,准确度相对深度学习较低,上一章节使用了dnn中的tensorflow,本章使用yolov3模型,识别出具体的分类。

Demo

320x320,置信度0.6

608x608,置信度0.6(.cfg里面是608)

yolov3模型下载

  • coco.names:模型具体的分类信息。https://github.com/pjreddie/darknet/blob/master/data/coco.names
  • yolov3.weights:权重文件https://pjreddie.com/media/files/yolov3.weights
  • yolov3.cfg:配置文件https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg
    以上若是下载不下来,提供其他下载地址,因为github非常慢。

CSDN:https://download.csdn.net/download/qq21497936/12995972
QQ群:1047134658(点击“文件”搜索“yolov3”,群内与博文同步更新)

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

操作步骤:yolov3

不同深度学习框架产生的模型,在操作上和数据输出上有一些区别。梳理下opencv使用tensorflow训练好的模型的使用步骤。

步骤一:读取分类文件

模型文件对应了不同的分类文件,分类文件是以行为标识,所在的行数(0开始),就是最终识别出的分类号的第几个分类。

std::string classesFile = "E:/qtProject/openCVDemo/dnnData/" "yolov3/coco.names"; // 读入分类名称,存入缓存 std::ifstream ifs(classesFile); std::vector<std::string> classes; std::string classLine; while(std::getline(ifs, classLine)) { classes.push_back(classLine); }

步骤二:加载模型和配置文件,建立神经网络。

根据不同的模型,使用cv::dnn::readNetFromXXX系列函数进行读取,opencv3.4.x系列支持的dnn模型(支持模型往上看)。
yolov3模型如下:

std::string modelWeights = "E:/qtProject/openCVDemo/dnnData/" "yolov3/yolov3.weights"; std::string modelCfg = "E:/qtProject/openCVDemo/dnnData/" "yolov3/yolov3.cfg"; // 加载yolov3模型 cv::dnn::Net net = cv::dnn::readNetFromDarknet(modelCfg, modelWeights); if(net.empty()) { qDebug() << __FILE__ << __LINE__ << "net is empty!!!"; return; }

步骤三:将要预测的图片加入到神经网络中

加入之后,需要识别图片,那么需要把图片输入到神经网络当中去,使用yolov3模型特别注意,要先进行归一化,然后变成指定大小的图片,如下:

// 读取图片识别 mat = cv::imread("E:/testFile/15.jpg"); if(!mat.data) { qDebug() << __FILE__ << __LINE__ << "Failed to read image!!!"; return; } // cv::dnn::blobFromImage(mat, blob); // 必须要设置,否则会跑飞 cv::dnn::blobFromImage(mat, blob, 1.0f/255, cv::Size(320, 320), cv::Scalar(0, 0, 0), true, false); net.setInput(blob);

宽度高度增加可以提升检测的准确度,最好是根据cfg文件进行修改,本Demo是320x320,实际.cfg文件中的是608x608,并且经过测试,这个是识别效果最好的像素,大于608则会跑飞。

步骤四:分类预测,获取识别的结果

输入之后,就进行识别,识别是向前预测(分类预测),并且拿到结果,对于yolov3模型,规定了有3个输出层,所以需要先获取3个输出层,然后预测的时候就需要指定预测这3个输出层,否则会跑飞。

// 获取输出的层 std::vector<cv::String> outPutNames; std::vector<int> outLayers = net.getUnconnectedOutLayers(); for(int index = 0; index < outLayers.size(); index++) { outPutNames.push_back(layerNames[outLayers[index] - 1]); qDebug() << __FILE__ << __LINE__ << QString(layerNames[outLayers[index] - 1].c_str()); } // 推理预测:可以输入预测的图层名称 std::vector<cv::Mat> probs; net.forward(probs, outPutNames);

对于预测的结果,存于std::vectorcv::Mat类型的probs,每一个元素指定为cv::Mat类型的prob,每一行代表一个检测到的分类,具体列信息如下表:

(注意:具体的使用,请参照“步骤五”)

步骤五:对达到置信度的可以通过输出的mat进行分类和框选

关键的输出结果步骤,不同的识别有区别,yolov3如下图:

// 置信度预制,大于执行度的将其使用rect框出来 for(int index = 0; index < probs.size(); index++) { for (int row = 0; row < probs[index].rows; row++) { // 获取probs中一个元素里面匹配对的所有对象中得分最高的 cv::Mat scores = probs[index].row(row).colRange(5, probs[index].cols); cv::Point classIdPoint; double confidence; // Get the value and location of the maximum score cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint); if(confidence > 0.6) { qDebug() << __FILE__ << __LINE__ << confidence << classIdPoint.x; int centerX = (int)(probs.at(index).at<float>(row, 0) * mat.cols); int centerY = (int)(probs.at(index).at<float>(row, 1) * mat.rows); int width = (int)(probs.at(index).at<float>(row, 2) * mat.cols); int height = (int)(probs.at(index).at<float>(row, 3) * mat.rows); int left = centerX - width / 2; int top = centerY - height / 2; cv::Rect objectRect(left, top, width, height); cv::rectangle(mat, objectRect, cv::Scalar(255, 0, 0), 2); cv::String label = cv::format("%s:%.4f", classes[classIdPoint.x].data(), confidence); cv::putText(mat, label, cv::Point(left, top - 10), cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 255)); qDebug() << __FILE__ << __LINE__ << centerX << centerY << width << height; } } }

函数原型

读取yolov3模型与配置文件函数原型

Net readNetFromDarknet(const String &cfgFile, const String &darknetModel = String());

从文件中读取。

  • 参数一:带有网络体系结构文本描述的.cfg文件的路径;
  • 参数二:已学习网络的.weights文件的路径;

读取图片(需要识别的)函数原型

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);.

从图像创建区域。可选择从中心调整和裁剪图像。

  • 参数一:图像输入图像(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深度。
  • 参数二:输入层的名称。
  • 参数三:可选的标准化刻度。
  • 参数四:可选的平均减去值。

返回所有层的名称(按照本身的索引循序排列)

std::vector<String> getLayerNames() const;

返回具有未连接输出的层的索引。

std::vector<int> getUnconnectedOutLayers() const;

深度检测识别(向前预测)函数原型

void cv::dnn::Net::Mat forward(const String& outputName = String());

向前预测,返回指定层的第一个输出的blob,一般是返回最后一层,可使用cv::Net::getLayarNames()获取所有的层名称。

  • 参数一:outputName需要获取输出的层的名称

Demo

void OpenCVManager::testYoloV3() { std::string classesFile = "E:/qtProject/openCVDemo/dnnData/" "yolov3/coco.names"; std::string modelWeights = "E:/qtProject/openCVDemo/dnnData/" "yolov3/yolov3.weights"; std::string modelCfg = "E:/qtProject/openCVDemo/dnnData/" "yolov3/yolov3.cfg"; // 读入分类名称,存入缓存 std::ifstream ifs(classesFile); std::vector<std::string> classes; std::string classLine; while(std::getline(ifs, classLine)) { classes.push_back(classLine); } // 加载yolov3模型 cv::dnn::Net net = cv::dnn::readNetFromDarknet(modelCfg, modelWeights); 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()); // 获取输出的层 std::vector<cv::String> outPutNames; std::vector<int> outLayers = net.getUnconnectedOutLayers(); for(int index = 0; index < outLayers.size(); index++) { outPutNames.push_back(layerNames[outLayers[index] - 1]); qDebug() << __FILE__ << __LINE__ << QString(layerNames[outLayers[index] - 1].c_str()); } while(true) { // 读取图片识别 mat = cv::imread("E:/testFile/15.jpg"); if(!mat.data) { qDebug() << __FILE__ << __LINE__ << "Failed to read image!!!"; return; } // cv::dnn::blobFromImage(mat, blob); // 必须要设置,否则会跑飞 cv::dnn::blobFromImage(mat, blob, 1.0f/255, cv::Size(320, 320), cv::Scalar(0, 0, 0), true, false); net.setInput(blob); // 推理预测:可以输入预测的图层名称 std::vector<cv::Mat> probs; net.forward(probs, outPutNames); // 显示识别花费的时间 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(255, 0, 0)); // 置信度预制,大于执行度的将其使用rect框出来 for(int index = 0; index < probs.size(); index++) { for (int row = 0; row < probs[index].rows; row++) { // 获取probs中一个元素里面匹配对的所有对象中得分最高的 cv::Mat scores = probs[index].row(row).colRange(5, probs[index].cols); cv::Point classIdPoint; double confidence; // Get the value and location of the maximum score cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint); if(confidence > 0.6) { qDebug() << __FILE__ << __LINE__ << confidence << classIdPoint.x; int centerX = (int)(probs.at(index).at<float>(row, 0) * mat.cols); int centerY = (int)(probs.at(index).at<float>(row, 1) * mat.rows); int width = (int)(probs.at(index).at<float>(row, 2) * mat.cols); int height = (int)(probs.at(index).at<float>(row, 3) * mat.rows); int left = centerX - width / 2; int top = centerY - height / 2; cv::Rect objectRect(left, top, width, height); cv::rectangle(mat, objectRect, cv::Scalar(255, 0, 0), 2); cv::String label = cv::format("%s:%.4f", classes[classIdPoint.x].data(), confidence); cv::putText(mat, label, cv::Point(left, top - 10), cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 255)); qDebug() << __FILE__ << __LINE__ << centerX << centerY << width << height; } } } cv::imshow(_windowTitle.toStdString(), mat); cv::waitKey(0); } }

对应工程模板v1.65.0

openCVDemo_v1.65.0_基础模板_yolov3分类检测.rar。

入坑

入坑一:加载模型时候错误

错误

原因
模型文件加载错误。解决
检查文件是否存在,路径是否正确,模型文件是否能对应上。

入坑二:输入blob时错误

错误

原因
预测的时候未输入参数,需要输入参数(注意:tensorflow未输入没有问题)。解决

上一篇:《OpenCV开发笔记(七十二):红胖子8分钟带你使用opencv+dnn+tensorFlow识别物体》
下一篇:持续补充中…

mat opencv 修改roi_OpenCV开发笔记(七十三):红胖子8分钟带你使用opencv+dnn+yolov3识别物体...相关推荐

  1. OpenCV开发笔记(七十二):红胖子8分钟带你使用opencv+dnn+tensorFlow识别物体

    本博客是转载的 本文章源博客地址:https://blog.csdn.net/qq21497936/article/details/109194717 各位读者,知识无穷而人力有穷,要么改需求,要么找 ...

  2. cv dnn识别动作规范 open_OpenCV开发笔记(七十三):红胖子8分钟带你使用opencv+dnn+yolov3识别物体...

    前言 级联分类器的效果并不是很好,准确度相对深度学习较低,上一章节使用了dnn中的tensorflow,本章使用yolov3模型,识别出具体的分类. Demo 320x320,置信度0.6 608x6 ...

  3. OpenCV开发笔记(六十九):红胖子8分钟带你使用传统方法识别已知物体(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,转载请注明出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/107837715 各位读者,知识无穷而人力有穷,要 ...

  4. getvalue参数计数不匹配_OpenCV开发笔记(六十八):红胖子8分钟带你使用特征点Flann最邻近差值匹配识别...

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  5. OpenCV开发笔记(七十一):红胖子8分钟带你深入级联分类器训练

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/109096211 各位读者,知识无穷而人力有穷 ...

  6. OpenCV开发笔记(六十三):红胖子8分钟带你深入了解SIFT特征点(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  7. OpenCV开发笔记(五十四):红胖子8分钟带你深入了解Haar级联分类器进行人脸检测(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  8. OpenCV开发笔记(五十二):红胖子8分钟带你深入了解直方图对比匹配(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  9. OpenCV开发笔记(五十八):红胖子8分钟带你深入了解图像的矩(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  10. OpenCV开发笔记(五十五):红胖子8分钟带你深入了解Haar、LBP特征以及级联分类器识别过程(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

最新文章

  1. 《C语言及程序设计》实践参考——当年第几天
  2. java前端长连接框架_Java如何实现长连接
  3. 【Geek软技能】程序员,为什么写不好一份简历?
  4. 2016年第七届蓝桥杯 - 国赛 - Java大学C组 - I. 路径之谜
  5. 批处理--创建当前日期的文件夹
  6. 集合去重 (集合元素为引用类型)--- java 8 新特性 --- 根据元素单属性、多属性实现去重
  7. java范形_java为什么要用范(泛)型?
  8. java8怎么按照两个字段的乘积排序_django-orm F对象的使用 按照两个字段的和,乘积排序实例...
  9. 学员使用移动端进行自学的视频动画html,Html5移动端获奖无缝滚动动画实现
  10. 小学计算机教室管理制度范本,《中小学微机室规章制度》.doc
  11. linux中eclipse不运行,linux下启动不了eclipse
  12. linux curl post/put请求
  13. 【Linux】文件描述符与重定向
  14. md5util java_Java 工具类 - MD5Util
  15. make指定输出目录
  16. 《数据挖掘导论》绪论
  17. 【目标跟踪系列】Struck: Structured Output Tracking with Kernels(代码调试运行篇)
  18. 商业智能BI与业务管理决策思维之三:业务质量分析
  19. centos shell基础 alias 变量单引号 双引号 history 错误重定向 21 jobs 环境变量 .bash_history source配置文件 nohup ...
  20. python 之复数

热门文章

  1. 初步解决网同客户端升级后局域网不能上网的问题
  2. 通过 Socket 实现 TCP 编程入门
  3. u大师制作linux系统,U大师官方下载|U大师U盘启动盘制作工具官方版 v4.7.37.56 最新版 - 系统天堂...
  4. 5月份鸿蒙升级时间,事关所有华为手机用户,鸿蒙正式升级时间终于确定
  5. C# action 返回值_C#与ABB机械手建立通信,并控制机械手动作 - 龙拓电子
  6. 拓扑排序:LC 207. 课程表 210. 课程表 II
  7. 解决Ubuntu 14.04下CodeBlocks缩进异常问题
  8. java定时发送_Java 定时发送邮件 | 学步园
  9. mysql之join_mysql学习之join用法
  10. Step By Step(1),Build Convolutional Neural Networks