OpenCV DNN之YOLO实时对象检测

OpenCV DNN之YOLO实时对象检测

OpenCV在3.3.1的版本中开始正式支持Darknet网络框架并且支持YOLO1与YOLO2以及YOLO Tiny网络模型的导入与使用。YOLO是一种比SSD还要快的对象检测网络模型,算法作者在其论文中说FPS是Fast R-CNN的100倍,基于COCO数据集跟SSD网络的各项指标对比

在最新的OpenCV3.4上我也测试了YOLO3,发现不支持,因为YOLO3有个新层类型shortcut,OpenCV3.4的Darknet暂时还不支持。这里首先简单的介绍一下YOLO网络基本结构,然后在通过代码演示Darknet支持的YOLO在OpenCV使用。

一:YOLO网络

对象检测网络基本上可以分为两种,一种称为两步法、另外一种称为一步法,很显然基于图像分类加上滑动窗口的方式最早的R-CNN就是两步法的代表之一,两步法的前面基本上是一个卷积神经网络,可以是VGGNet或者Inception之类的,然后再加上一个滑动窗口,但是这种方法太慢,所以就有了区域推荐(RP),预先推荐一些感兴趣的区域,进行预言,这些方法普遍有一个缺点,计算量比较大,导致性能低下无法实时,而YOLO采样了一种完全不同的方法,达到对图像每个区域只计算一次(You Look at Once - YOLO),YOLO把图像分为13x13的Cell(网格):

每个Cell预测5个BOX,同时YOLO也会生成一个置信分数,告诉每个BOX包含某个对象的可能性是多少,注意置信分数不会直接说明BOX内是检测到何种对象,最终那些得分高的BOX被加粗显示如下:

对于每个BOX来说,Cell会预测检测对象类别,这部分的工作就像是一个分类器一样,基于VOC数据集20中对象检测,YOLO结合分数与分类信息对每个BOX给出一个最终可能对象类型的可能性值,如下图,×××区域85%可能性是狗:

因为总数是13x13的网格,每个网格预言5个BOX,所以最终有854个BOX,证据表明绝大多数的BOX得分会很低,我们只要保留30%BOX即可(取决于你自己的阈值设置),最终输出:

从上面可以看出整个图像只是被计算了一次,真正做到了降低计算量,提高了检测实时性。上述检测使用的YOLO的网络结构如下:

发现只有CNN层,没有FC层,是不是简单到爆,最后说一下为什么最后一层卷积层深度是125,
因为每个Cell检测5个BOX,对每个BOX来说,包含如下数据

  • BOX本身信息,x、y、w、h
  • 置信分数
  • 基于VOC数据集的20个对象类别

所以对每个BOX来说有25个参数,5个BOX= 5x25=125个参数。
上面是得到的网络模型就是tiny-YOLO网络模型,可以在移动端实时对象检测。这个跟作者在论文中提到的稍微有点差异,论文中作者是输入图像为448x448,分为7x7的网格(Cell),结构如下:

最终输出是每个Cell预测两个BOX,做20个分类,它得到最终是

  • BOX本身信息,x、y、w、h
  • 置信分数

深度 = SS(B5+20), 其中20个表示分类数目,S表示网络分割,B表示BOX个数。S=7、B=2,最终输出是77*30

二:在OpenCV中使用YOLO

OpenCV在3.3.1版本中开始支持Darknet,可能有人会问,Darknet是什么鬼,它是YOLO的作者自己搞出来的深度学习框架,支持C/C++/Python语言,支持YOLOv1、YOLOv2、YOLOv3等网络模型训练与使用。但是在OpenCV只是前馈网络,只支持预测,不能训练。OpenCV中基于YOLO模型我使用的是tiny-YOLO网络模型,支持20中对象检测。代码实现步骤如下:
1. 加载网络模型

String modelConfiguration = "D:/vcprojects/images/dnn/yolov2-tiny-voc/yolov2-tiny-voc.cfg";
String modelBinary = "D:/vcprojects/images/dnn/yolov2-tiny-voc/yolov2-tiny-voc.weights";
dnn::Net net = readNetFromDarknet(modelConfiguration, modelBinary);
if (net.empty())
{
    printf("Could not load net...\n");
    return;
}

2. 加载分类信息

vector<string> classNamesVec;
ifstream classNamesFile("D:/vcprojects/images/dnn/yolov2-tiny-voc/voc.names");
if (classNamesFile.is_open())
{
    string className = "";
    while (std::getline(classNamesFile, className))
        classNamesVec.push_back(className);
}

3. 加载测试图像

// 加载图像
Mat frame = imread("D:/vcprojects/images/fastrcnn.jpg");
Mat inputBlob = blobFromImage(frame, 1 / 255.F, Size(416, 416), Scalar(), true, false);
net.setInput(inputBlob, "data");

4. 检测与显示

// 检测
Mat detectionMat = net.forward("detection_out");
vector<double> layersTimings;
double freq = getTickFrequency() / 1000;
double time = net.getPerfProfile(layersTimings) / freq;
ostringstream ss;
ss << "detection time: " << time << " ms";
putText(frame, ss.str(), Point(20, 20), 0, 0.5, Scalar(0, 0, 255));

// 输出结果
for (int i = 0; i < detectionMat.rows; i++)
{
    const int probability_index = 5;
    const int probability_size = detectionMat.cols - probability_index;
    float *prob_array_ptr = &detectionMat.at<float>(i, probability_index);
    size_t objectClass = max_element(prob_array_ptr, prob_array_ptr + probability_size) - prob_array_ptr;
    float confidence = detectionMat.at<float>(i, (int)objectClass + probability_index);
    if (confidence > confidenceThreshold)
    {
        float x = detectionMat.at<float>(i, 0);
        float y = detectionMat.at<float>(i, 1);
        float width = detectionMat.at<float>(i, 2);
        float height = detectionMat.at<float>(i, 3);
        int xLeftBottom = static_cast<int>((x - width / 2) * frame.cols);
        int yLeftBottom = static_cast<int>((y - height / 2) * frame.rows);
        int xRightTop = static_cast<int>((x + width / 2) * frame.cols);
        int yRightTop = static_cast<int>((y + height / 2) * frame.rows);
        Rect object(xLeftBottom, yLeftBottom,
            xRightTop - xLeftBottom,
            yRightTop - yLeftBottom);
        rectangle(frame, object, Scalar(0, 0, 255), 2, 8);
        if (objectClass < classNamesVec.size())
        {
            ss.str("");
            ss << confidence;
            String conf(ss.str());
            String label = String(classNamesVec[objectClass]) + ": " + conf;
            int baseLine = 0;
            Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
            rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom),
                Size(labelSize.width, labelSize.height + baseLine)),
                Scalar(255, 255, 255), CV_FILLED);
            putText(frame, label, Point(xLeftBottom, yLeftBottom + labelSize.height),
                FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));
        }
    }
}
imshow("YOLO-Detections", frame);

5. 运行效果

我的课程:
学习OpenCV3.3深度神经网络(DNN)模块-应用视频教程

原文地址:http://blog.51cto.com/gloomyfish/2095418

时间: 2024-10-07 07:27:51

OpenCV DNN之YOLO实时对象检测的相关文章

【YOLO】实时对象检测使用体验

官网:https://pjreddie.com/darknet/yolo/ 以下全部在服务器上完成,服务器上是有opencv等. 1.安装Darknet git clone https://github.com/pjreddie/darknet cd darknet make 2.下载预先训练的权重文件(258 MB).或者只是运行这个: wget https://pjreddie.com/media/files/yolo.weights 3.运行检测器 ./darknet detect cfg

一文带你学会使用YOLO及Opencv完成图像及视频流目标检测(上)|附源码

计算机视觉领域中,目标检测一直是工业应用上比较热门且成熟的应用领域,比如人脸识别.行人检测等,国内的旷视科技.商汤科技等公司在该领域占据行业领先地位.相对于图像分类任务而言,目标检测会更加复杂一些,不仅需要知道这是哪一类图像,而且要知道图像中所包含的内容有什么及其在图像中的位置,因此,其工业应用比较广泛.那么,今天将向读者介绍该领域中表现优异的一种算算法--"你只需要看一次"(you only look once,yolo),提出该算法的作者风趣幽默可爱,其个人主页及论文风格显示了其性

[OpenCV-Python] OpenCV 中计算摄影学 部分 IX 对象检测 部分 X

部分 IX计算摄影学 49 图像去噪目标 ? 学习使用非局部平均值去噪算法去除图像中的噪音 ? 学习函数 cv2.fastNlMeansDenoising(),cv2.fastNlMeansDenoisingColored()等原理 在前面的章节中我们已经学习了很多图像平滑技术,比如高斯平滑,中值平滑等,当噪声比较小时这些技术的效果都是很好的.在这些技术中我们选取像素周围一个小的邻域然后用高斯平均值或者中值平均值取代中心像素.简单来说,像素级别的噪声去除是限制在局部邻域的.噪声有一个性质.我们认

opencv学习---运动目标(前景)检测

opencv学习---运动目标(前景)检测 1.帧差法 原理:视频序列相邻两帧或三帧间采用基于像素的时间差分,通过闭值化来提取出图像中的运动区域. 优点:算法简单.计算量小,无需训练背景,对缓慢变换的光照不是很敏感. 缺点:容易受天气.阴影及杂乱背景干扰,阈值T的选择相当关键,稳定性差. 2.背景差分法 原理:用背景的参数模型来近似背景图像,将当前帧与背景图像进行差分比较实现对运动区域的检测 优点:计算量小,较高的实时性,利用已有帧信息进行背景动态更新 缺点:如何建立对于不同场景的动态变化均具有

携程实时智能检测平台建设实践

一.背景介绍 1.规则告警带来的问题 大部分监控平台是基于规则告警实现监控指标的预警.规则告警一般基于统计学,如某个指标同比.环比连续上升或下降到一定阈值进行告警.规则告警需要用户较为熟悉业务指标的形态,从而才能较为准确的配置告警阈值,这样带来的问题是配置规则告警非常繁琐.告警效果也比较差,需要大量人力物力来维护规则告警.当一个告警产生时,也需要耗费许多人力验证告警是否正确并确认是否需要重新调整阈值.在携程,规则告警还涉及了其它问题,比如携程光公司级别的监控平台就有三个,每个业务部门还会根据自己

【OpenCV入门教程之十七】OpenCV重映射 &amp; SURF特征点检测合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/30974513 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 知乎:http://www.zhihu.com/people/mao-xing-yun 邮箱: [email protected] 写作当前博文时配套使用的OpenCV版本: 2.4.9 本篇文章中,我们一起探讨了OpenCV中

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

OpenCV+海康威视摄像头的实时读取

OpenCV+海康威视摄像头的实时读取 环境 硬件: PC:i7-4970 16GB内存 摄像头型号:DS-2CD3310D-I(2.8mm) 软件: windows-x64.vs2012.opencv2.4.8.hkvision5114-x64版本库 配置 保证使用SADP工具可以识别摄像头,然后配置IP与电脑在同一个网段. 再保证可以从浏览器中访问.账号密码默认的一般是admin.a123456789(老版本的摄像头密码是12345). 登录成功后可能要求下载WebComponent控件,下

吴恩达【深度学习工程师】 04.卷积神经网络 第三周目标检测 (1)基本的对象检测算法

该笔记介绍的是<卷积神经网络>系列第三周:目标检测(1)基本的对象检测算法 主要内容有: 1.目标定位 2.特征点检测 3.目标检测  目标定位 使用算法判断图片中是不是目标物体,如果是还要再图片中标出其位置并使用边框标记出来                          我们研究过的问题中,图片分类的思想可以帮助学习分类定位,而分类定位的思想又可以帮助学习对象检测 a.分类定位问题,通常有一个较大的对象位于图片中间位置. b.对象检测问题,图片可以含有多个对象,或一张图片中会有多个不同分