OpenCV通过YOLOv3模型实现目标检测

一、OpenCV DNN 简介

OpenCV中的深度学习模块(DNN)只提供了推理功能,不涉及模型的训练,支持多种深度学习框架,比如TensorFlow,Caffe,Torch和Darknet。

  • opencv 无法训练模型,但它支持载入其他深度学习框架训练好的模型,并使用该模型进行预测 inference;
  • opencv 在载入模型时会使用 dnn 模块对模型进行重写,使得模型运行效率更高。

img

**轻量型:**DNN模块只实现了推理功能,代码量及编译运行开销远小于其他[深度学习模型框架。

**使用方便:**DNN模块提供了内建的CPU和GPU加速,无需依赖第三方库,若项目中之前使用了OpenCV,那么通过DNN模块可以很方便的为原项目添加深度学习的能力。

通用性: DNN模块支持多种网络模型格式,用户无需额外的进行网络模型的转换就可以直接使用,支持的网络结构涵盖了常用的目标分类,目标检测和图像分割的类别。

支持多种运算设备: DNN模块支持多种运算设备(CPU,GPU等)和操作系统(Linux,windows,MacOS等)。

二、YOLO简介

YOLO (You Only Look Once) 是一种实时目标检测模型,它采用卷积神经网络CNN直接回归边界框(bounding box)的位置及其所属类别。

官方地址为:

https://pjreddie.com/darknet/yolo/

在这里插入图片描述

Github地址为:

https://github.com/pjreddie/darknet/tree/master

在这里插入图片描述

三、OpenCV加载YOLO模型实现目标检测

我们通过 OpenCV的DNN模块加载YOLO模型,并进行物体识别。

1、加载Yolo模型

在C++中调用Yolo模型之前,我们需要加载模型并进行初始化。以下是加载Yolo模型的基本步骤:

① 使用OpenCV读取图像

cv::Mat image = cv::imread("image.jpg");

② 定义Yolo模型配置文件和权重文件的路径

std::string configPath = "yolov3.cfg";
std::string weightPath = "yolov3.weights";

③ 加载Yolo模型配置文件和权重文件

cv::dnn::Net net = cv::dnn::readNetFromDarknet(configPath, weightPath);

加载完成后,我们就可以使用Yolo模型进行目标检测了。

2、Yolo数据集下载

YOLO模型需要配置文件、权重文件和识别问价,下面列出获取方式。

① 获取配置和权重文件

定义Yolo模型配置文件和权重文件分别为"yolov3.cfg""yolov3.weights" ,需要获取。

获取对应的.cfg文件和.weights文件:

地址:

点击下面的红框框即可下载。

img

备注: 我下载使用的是 《YOLOv3-416》。

在这里插入图片描述

② 获取yolov3.txt配置文件

当识别物体对应的名称时使用到 "object_detection_classes_yolov3.txt" 配置文件,下载地址如下:

https://github.com/arunponnusamy/object-detection-opencv/tree/master

在这里插入图片描述

  • object_detection_classes_yolov3.txt 内容:
person
bicycle
car
motorcycle
airplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
couch
potted plant
bed
dining table
toilet
tv
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush
③ 整理数据集

创建 models/yolov3/ 目录,将 yolov3.cfgyolov3.weightsobject_detection_classes_yolov3.txt 放到 models/yolov3/ 目录下。

在这里插入图片描述

3、C++示例工程

① 源代码
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <opencv2/dnn.hpp>
#include <opencv2/opencv.hpp>

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

//数据集:cfg和weights加载位置
String yolo_cfg = "C:\\VS2019Output\\OpencvDemo1\\models\\yolov3\\yolov3.cfg";
String yolo_model = "C:\\VS2019Output\\OpencvDemo1\\models\\yolov3\\yolov3.weights";

int main(int argc, char** argv)
{
	//加载网络模型
	Net net = readNetFromDarknet(yolo_cfg, yolo_model);

	//net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
	net.setPreferableTarget(DNN_TARGET_CPU);
	std::vector<String> outNames = net.getUnconnectedOutLayersNames();
	for (int i = 0; i < outNames.size(); i++) 
	{
		//输出各层信息
		printf("output layer name : %s\n", outNames[i].c_str());
	}

	//从类名文件中读取类名
	vector<string> classNamesVec;
	ifstream classNamesFile("C:\\VS2019Output\\OpencvDemo1\\models\\yolov3\\object_detection_classes_yolov3.txt");
	if (classNamesFile.is_open())
	{
		string className = "";
		while (std::getline(classNamesFile, className))
			classNamesVec.push_back(className);
	}

	// 加载图像 
	Mat frame = imread("volo3.png");
	Mat inputBlob = blobFromImage(frame, 1 / 255.F, Size(416, 416), Scalar(), true, false);
	net.setInput(inputBlob);

	// 检测
	std::vector<Mat> outs;
	net.forward(outs, outNames);
	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));
	vector<Rect> boxes;
	vector<int> classIds;
	vector<float> confidences;
	for (size_t i = 0; i < outs.size(); ++i)
	{
		// Network produces output blob with a shape NxC where N is a number of
		// detected objects and C is a number of classes + 4 where the first 4
		// numbers are [center_x, center_y, width, height]
		float* data = (float*)outs[i].data;
		for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols)
		{
			Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
			Point classIdPoint;
			double confidence;
			minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
			if (confidence > 0.5)
			{
				int centerX = (int)(data[0] * frame.cols);
				int centerY = (int)(data[1] * frame.rows);
				int width = (int)(data[2] * frame.cols);
				int height = (int)(data[3] * frame.rows);
				int left = centerX - width / 2;
				int top = centerY - height / 2;

				classIds.push_back(classIdPoint.x);
				confidences.push_back((float)confidence);
				boxes.push_back(Rect(left, top, width, height));
			}
		}
	}

	vector<int> indices;
	NMSBoxes(boxes, confidences, 0.5, 0.2, indices);
	for (size_t i = 0; i < indices.size(); ++i)
	{
		int idx = indices[i];
		Rect box = boxes[idx];
		String className = classNamesVec[classIds[idx]];
		putText(frame, className.c_str(), box.tl(), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2, 8);
		rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0);
	}

	imshow("YOLOv3-Detections", frame);
	waitKey(0);

	return 0;
}
② 运行效果

在这里插入图片描述

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值