【YOLO学习笔记】之YOLO初体验

版权声明: https://blog.csdn.net/shuiyixin/article/details/82468870

马上就要开始写毕业论文了,定题目是一件很痛苦的事情,普通的管理系统不想写(根本原因在于没有架构思维,没有真正的软件工程思想,不懂业务需求,不明白业务逻辑,不想写一个所谓的管理系统糊弄事)所以上网查阅资料,问同学,终于,我和YOLO邂逅了。

所以小编开始上网查找YOLO,然后。。。。

(笑十分钟,写什么毕业论文,享受人生去,不得不说,这个学期,事挺多的,是有点忙不过来,但是该做的还得做啊。)

那YOLO是什么呢?且听我慢慢道来。

一、YOLO怎么出生的?

1、出生前

在深度神经网络之前,早期的 Object detection (目标检测)方法是通过提取图像的一些 robust 的特征如( Haar,SIFT,HOG )等特征,使用 DPM 模型,用 silding window 的方式来预测具有较高 score 的 bounding box。这种方式非常耗时,而且精度又不怎么高。

有用过OpenCV的童鞋,可能了解过,OpenCV自带脸部检测功能,用到的就是Haar分类器。

后来出现了CNN,RCNN等神经网络,精度大幅度提高(逼格也大幅度提高)。

2、出生时——YOLO v1

2015年,Joseph Redmon和Ali Farhadi等人提出的基于单个神经网络的目标检测系统,完成了著名的论文《You Only Look Once: Unified, Real-Time Object Detection》,即我们今天所用的第一个版本YOLO v1。这是继 RCNN,fast-RCNN 和 faster-RCNN之后,Ross Girshick 针对 DL 目标检测速度问题提出的另外一种框架。YOLO V1 其增强版本在 GPU 上能跑45fps,简化版本155fps。

扫描二维码关注公众号,回复: 3249120 查看本文章

论文下载:http://arxiv.org/abs/1506.02640

代码下载:https://github.com/pjreddie/darknet 

3、第一次“升级”——YOLO v2

为提高物体定位精准性和召回率,YOLO作者在2017年的CVPR发表论文 《YOLO9000: Better, Faster, Stronger》 即提出了YOLO v2,相比v1提高了训练图像的分辨率;引入了faster rcnn中anchor box的思想,对网络结构的设计进行了改进,输出层使用卷积层替代YOLO的全连接层,联合使用coco物体检测标注数据和imagenet物体分类标注数据训练物体检测模型。相比YOLO,YOLO9000在识别种类、精度、速度、和定位准确性等方面都有大大提升。

4、第二次“升级”——YOLO v3

后来,YOLO作者进一步推出v3,速度更快,准确度更高,YOLO V3在Pascal Titan X上处理608x608图像速度达到20FPS,在 COCO test-dev 上 [email protected] 达到 57.9%,与RetinaNet的结果相近,并且速度快了4倍。  YOLO V3的模型比之前的模型复杂了不少,可以通过改变模型结构的大小来权衡速度与精度。有图为证:

作者对YOLO v3的赞赏如下:

YOLOv3 is extremely fast and accurate. In mAP measured at .5 IOU YOLOv3 is on par with Focal Loss but about 4x faster. Moreover, you can easily tradeoff between speed and accuracy simply by changing the size of the model, no retraining required.

二、YOLO怎么使用

开山之作YOLO v1,它的出生就决定了它的独特所在,相比R-CNN、Fast R-CNN,它有着自己独特的魅力,以至于V2,V3急速火爆。

但是我们想对YOLO有一个深入的了解,当然是先使用一下,了解一下它用起来怎么样,通过实战,来一步一步深入了解,深入学习YOLO。

1、配置

配置最重要,特别是我们要做的是深度学习与计算机视觉,不仅要求硬件,还要求软件。

在这里,我们不需要一个特别强大的GPU(有了最好),一个win7或者win10的电脑(win8也可以,但是win8现在很少使用,大多数程序员都偏爱win7)

我个人偏爱C++,所以我的编程语言用的是C++,如果各位对java,Python或者其他适合深度学习、人工智能的编程语言,大家可以根据原理自己编写,希望大家能够集思广益。

软件要求如下:

VS2015:网上下载,多的很,然后上网查找密钥登陆即可永久免费。

OpenCV3.4.0:下载地址

YOLO相关文件:下载地址(同时附赠本文所有源码)

安装及配置教程:请点击安装配置教程,即可查看。

2、代码解析

1.头文件

关于头文件的引用,因为用到黑窗体,需要输入输出,还要涉及到图形图像处理,需要调用opencv的一些头文件需要应用文件处理,文件处理相关头文件……

#pragma once
#include"stdafx.h"
#include<opencv2\opencv.hpp>
#include<opencv2\dnn.hpp>
#include<fstream>
#include<iostream>
#include<algorithm>
#include<cstdlib>

using namespace std;
using namespace cv;
using namespace cv::dnn;

2.全局变量

还需要用到一些全局变量,yolov2-tiny-voc.cfg是YOLO的配置文件(后续会有详细讲解),yolov2-tiny-voc.weights是作者训练出来的权重文件,用来识别物体,比如下面这个图像上的是猫。

voc.names是YOLO作者在YOLO V1 中训练出来的20种物体的一个集合,包括:aeroplane、bicycle、bird、boat、bottle、bus、car、cat、chair、cow、diningtable、dog、horse、motorbike、person、pottedplant、sheep、sofa、train、tvmonitor。

float confidenceThreshold = 0.1;
String modelConfiguration = "yolov2-tiny-voc.cfg";//yolov2-tiny-voc.cfg
String modelBinary = "yolov2-tiny-voc.weights";
ifstream classNamesFile("voc.names");

这些文件都可以在我上面的链接下载使用,解压到cpp文件所在文件夹。

3.函数定义

做测试主要是对图像和视频的测试,图像就是通过imread获取图片,视频通过摄像头获取视频流。所以我定义了两个函数,在这里我没有优化,只是为了大家能够理解YOLO,而不是学习提升C++的编程能力。

int dnn_yolo_syx_Img();
int dnn_yolo_syx_Cam();

到这里,所有的前期准备工作,准备完成,接下来就是具体代码的理解,

4.函数实现

首先需要读入YOLO相关文件。

        dnn::Net net = readNetFromDarknet(modelConfiguration, modelBinary);
	//判断是否读入成功
	if (net.empty())
	{
		printf("Could not load net...\n");
		return -1;
	}

然后需要定义一个数组,用于存放20个可识别的种类。

        //定义一个string类的数组
	vector<string> classNamesVec;

	if (classNamesFile.is_open())
	{
		string className = "";
		while (std::getline(classNamesFile, className))
			classNamesVec.push_back(className);
	}

载入要识别的图像(小猫),并做一些处理

        // 加载图像
	Mat frame = imread("111.jpg");
	if (frame.empty())
	{
		printf("Could not load image...\n");
		return -1;
	}

	Mat inputBlob;
	inputBlob = blobFromImage(frame, 1 / 255.F, Size(416, 416), Scalar(), true, false);
	net.setInput(inputBlob, "data");

接下来是对图像上的物体做检测,并实时推送检测消耗时间。

        // 检测
	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)
		{
			//语句见下一个代码块
		}
	}

由于这段代码有点多,所以就分开来写,方便大家看懂其中的逻辑关系,下面是if语句里面的详细内容

                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())
			{
				

			}
		}

在上一个if语句块中还有一个if语句,详细内容如下:

        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, CV_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),
			CV_FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));

	}

最后就是将图像输出,让大家能够看到结果。

        imshow("YOLO-Detections", frame);
	waitKey(0);
	return 0;

输出图像如下:

大家可以自己写一下如何将上面的代码转化成识别摄像头读取的图像中的物体是什么?具体代码,大家也可以在YOLO相关文件中查找,大家有什么问题也可以在下面评论,我们一起相互交流。

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/shuiyixin/article/details/82468870
今日推荐