前言

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

Demo

320x320,置信度0.6

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

yolov3模型下载

OpenCV深度识别基本流程

opencv3.4.x支持了各种模型。

支持的模型

操作步骤:yolov3

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

步骤一:读取分类文件

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

std::string classesFile = "E:/qtProject/openCVDemo/dnnData/" \

"yolov3/coco.names";

// 读入分类名称,存入缓存

std::ifstream ifs(classesFile);

std::vector<: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<:string> outPutNames;

std::vector 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<: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(row, 0) * mat.cols);

int centerY = (int)(probs.at(index).at(row, 1) * mat.rows);

int width = (int)(probs.at(index).at(row, 2) * mat.cols);

int height = (int)(probs.at(index).at(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 getLayerNames() const;

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

std::vector 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<: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<:string> layerNames = net.getLayerNames();

int lastLayerId = net.getLayerId(layerNames[layerNames.size() - 1]);

cv::Ptr<: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<:string> outPutNames;

std::vector 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<:mat> probs;

net.forward(probs, outPutNames);

// 显示识别花费的时间

std::vector 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(row, 0) * mat.cols);

int centerY = (int)(probs.at(index).at(row, 1) * mat.rows);

int width = (int)(probs.at(index).at(row, 2) * mat.cols);

int height = (int)(probs.at(index).at(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未输入没有问题)。

解决

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

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

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

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

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

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

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

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

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

  5. OpenCV开发笔记(四十九):红胖子8分钟带你深入了解轮廓识别(图文并茂+浅显易懂+程序源码)

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

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

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

  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/ ...

最新文章

  1. 数字货币 分层确定性钱包(HD Wallets)
  2. 图像模拟添加(产生)高斯噪声的OpenCV代码
  3. 用Windows Live Writer发布博客也可以不生成缩略图
  4. c语言最佳适应算法实验报告,操作系统实验报告---主存分配与回收(最佳适应算法)...
  5. Linux工作笔记-Linux常用命令(一)
  6. GLSL Optimizer
  7. 数据在本地文件的写入和读取
  8. signature=0142b13a38da3ce7be8fce0d56b678af,授权系统
  9. 掘金mysql_MySQL学习笔记(转自掘金小册 MySQL是怎样运行的,版权归作者所有!)
  10. 基于python的数字印刷体识别_不告诉你我用了它配合Python简简单单开发OCR识别,带你识别手写体、印刷体、身份证等N种,附代码!...
  11. [转]失业七个月,面试六十家公司的深圳体验(转贴)
  12. appium的安装+连接夜神模拟器控制app
  13. 选择排序(升序排列)
  14. Go语言与Java语言对比
  15. php正三角,php打印正三角形
  16. java计算机毕业设计疫情物质管理系统源码+数据库+lw文档+系统+部署
  17. 钱币兑换问题 HDU 1284
  18. 大学生实习行为十要(转)
  19. pinia的学习和理解
  20. android数据库工具库,android 数据库工具种MyDbHelper

热门文章

  1. 搭建WAMP 环境时,解决Windows下输入localhost找不到网页的问题
  2. 百度云 ajax jquery 三级联动,jQuery ajax实现省市县三级联动
  3. vue - 响应式原理梳理(一)
  4. 巴克莱:对冲基金AI和大数据工作指南
  5. MySQL--4操作数据表中的记录小结
  6. 增加XP的IIS连接数,解决403.9连接用户过多的问题
  7. 小教活动总结-VB即时通讯小程序
  8. 绝了!一个妹子 rm -rf 把公司整个数据库删没了
  9. 历史上最简单的一道Java面试题,但无人能通过
  10. 微服务架构如何保证安全性?