c++调用yolov4模型进行目标检测-使用opencv4.4.0

2023-05-16

前言

最近刚出的opencv4.4.0也支持了yolov4,便尝试用opencv调用yolov4进行检测,做个记录。当然,yolov3、yolov4-tiny等也能调用,只需修改加载的cfg和weight文件就行。如果想使用GPU加速的话,需要安装opencv的GPU版,可以参考:ubuntu下安装opencv,并配置DNN模块使用CUDA加速

下载

1、yolov4权重

地址:百度网盘
提取码:2zfk

2、源码

代码我放到github上了,看这里

步骤

最近在做一个项目,其中把yolov4检测部分封装成了一个Detection类,下面的代码是从中分出来的修改的,先给出成员变量:

	//图像属性
	int m_width;			//图像宽度
	int m_height;			//图像高度
	//网络处理相关
	Net m_model;			//网络模型
	Mat m_frame;			//每一帧
	Mat m_blob;				//从每一帧创建一个4D的blob用于网络输入
	vector<Mat> m_outs;		//网络输出
	vector<float> m_confs;	//置信度
	vector<Rect> m_boxes;	//检测框左上角坐标、宽、高
	vector<int> m_classIds;	//类别id
	vector<int> m_perfIndx;	//非极大阈值处理后边界框的下标
	//检测超参数
    int m_inpWidth;			//网络输入图像宽度
	int m_inpHeight;		//网络输入图像高度
	float m_confThro;		//置信度阈值
	float m_NMSThro;		//NMS非极大抑制阈值
	vector<string> m_classes; //类别名称
1、网络加载

首先需要对yolov4进行加载,包括配置文件、模型权重、检测类别名称,即加载yolov4.cfg,yolov4.weights,coco.names三个文件。

//读取网络模型和类别
void Detection::ReadModel()
{	
	string classesFile = "./yolo/coco.names";
    String modelConfig = "./yolo/yolov4.cfg";
    String modelWeights = "./yolo/yolov4.weights";
    //加载类别名
	ifstream ifs(classesFile.c_str());
	string line;
	while (getline(ifs, line)) m_classes.push_back(line);
	//加载网络模型
	m_model = readNetFromDarknet(modelConfig, modelWeights);
	//OPENCL
	m_model.setPreferableBackend(DNN_BACKEND_OPENCV);
	m_model.setPreferableTarget(DNN_TARGET_OPENCL);
	//GPU
	// m_model.setPreferableBackend(DNN_BACKEND_CUDA);
	// m_model.setPreferableTarget(DNN_TARGET_CUDA);
}
2、检测整体过程
//检测过程
bool Detection::Detecting(Mat frame)
{
    m_frame = frame.clone();

	//创建4D的blob用于网络输入
	blobFromImage(m_frame, m_blob, 1 / 255.0,Size(m_inpWidth, m_inpHeight), Scalar(0, 0, 0), true, false);

	//设置网络输入
	m_model.setInput(m_blob);

	//前向预测得到网络输出,forward需要知道输出层,这里用了一个函数找到输出层
	m_model.forward(m_outs, GetOutputsNames());

	//使用非极大抑制NMS删除置信度较低的边界框
	PostProcess();

    //画检测框
    Drawer();

	return true;
}
3、获取输出层名称
//获取网络输出层名称
vector<String> Detection::GetOutputsNames()
{
	static vector<String> names;
	if (names.empty())
	{
		//得到输出层索引号
		vector<int> outLayers = m_model.getUnconnectedOutLayers();
		
		//得到网络中所有层名称
		vector<String> layersNames = m_model.getLayerNames();
		
		//获取输出层名称
		names.resize(outLayers.size());
		for (int i = 0; i < outLayers.size(); ++i)
			names[i] = layersNames[outLayers[i] - 1];
	}
	return names;
}
4、对网络输出进行处理

主要是得出目标类别、置信度、检测框信息,被分别存到m_classIds、m_confs、m_boxes中,然后通过NMS找出每个目标最佳检测框的下标。

//使用非极大抑制NMS去除置信度较低的边界框
void Detection::PostProcess()
{
	for (int num = 0; num < m_outs.size(); num++)
	{
		Point Position;
		double confidence;

		//得到每个输出的数据
		float* data = (float*)m_outs[num].data;
		for (int j = 0; j < m_outs[num].rows; j++, data += m_outs[num].cols)
		{
			//得到该输出的所有类别的
			Mat scores = m_outs[num].row(j).colRange(5, m_outs[num].cols);

			//获取最大置信度对应的值和位置
			minMaxLoc(scores, 0, &confidence, 0, &Position);
			
			//对置信度大于阈值的边界框进行相关计算和保存
			if (confidence > m_confThro)
			{
				//data[0],data[1],data[2],data[3]都是相对于原图像的比例
				int centerX = (int)(data[0] * m_width);
				int centerY = (int)(data[1] * m_height);
				int width = (int)(data[2] * m_width);
				int height = (int)(data[3] * m_height);
				int left = centerX - width / 2;
				int top = centerY - height / 2;
				//保存信息
				m_classIds.push_back(Position.x);
				m_confs.push_back((float)confidence);
				m_boxes.push_back(Rect(left, top, width, height));
			}
		}
	}
	//非极大值抑制,以消除具有较低置信度的冗余重叠框
	NMSBoxes(m_boxes, m_confs, m_confThro, m_NMSThro, m_perfIndx);
}
5、画检测结果
//画出检测结果
void Detection::Drawer()
{
	//获取所有最佳检测框信息
	for (int i = 0; i < m_perfIndx.size(); i++)
	{
		int idx = m_perfIndx[i];
		Rect box = m_boxes[idx];
		DrawBoxes(m_classIds[idx], m_confs[idx], box.x, box.y,
			box.x + box.width, box.y + box.height);
	}
}


//画出检测框和相关信息
void Detection::DrawBoxes(int classId, float conf, int left, int top, int right, int bottom)
{
	//画检测框
	rectangle(m_frame, Point(left, top), Point(right, bottom), Scalar(255, 178, 50), 3);

	//该检测框对应的类别和置信度
	string label = format("%.2f", conf);
	if (!m_classes.empty())
	{
		CV_Assert(classId < (int)m_classes.size());
		label = m_classes[classId] + ":" + label;
	}

	//将标签显示在检测框顶部
	int baseLine;
	Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
	top = max(top, labelSize.height);
	rectangle(m_frame, Point(left, top - round(1.5*labelSize.height)), Point(left + round(1.5*labelSize.width), top + baseLine), Scalar(255, 255, 255), FILLED);
	putText(m_frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 0), 1);
}

测试

写了个test.cpp

#include "Detection.h"
#include <iostream>

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

void TestDetection()
{
	string image_path = "./data/test.jpg";
	string save_path = "./data/result.jpg";
    Mat img = imread(image_path);
    cout<<"width: "<<img.cols<<endl;
    cout<<"height: "<<img.rows<<endl;

	Detection detection = Detection();
	detection.Initialize(img.cols, img.rows);
	detection.Detecting(img);
	imwrite(save_path, detection.GetFrame());
	return;
}


int main()
{
	TestDetection();
	return 0;
}

检测结果

在这里插入图片描述
不得不说yolov4真的很腻害,左边海报上的小孩都能检测出来,我是没想到,定位也很准确。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++调用yolov4模型进行目标检测-使用opencv4.4.0 的相关文章

随机推荐

  • win11电脑开移动热点,但是手机连不上

    一 现象描述 电脑连接宽带 xff0c 然后用电脑开移动热点 前一天用手机连接热点的时候 xff0c 还是正常的 xff1b 今天连接的时候 xff0c 手机就显示 拒绝接入 寻找各种解决方法 xff0c 结果都无法解决我的问题 后来 xf
  • Android:使用RxJAva实现倒计时

    64 SuppressLint 34 SetTextI18n 34 private void startTimer mTvSend setEnabled false Observable intervalRange 1 60 0 1 Tim
  • linux的远程管理

    linux的远程管理 一 远程管理二 实现ssh远程管理无密码验证 一 远程管理 span class token comment 我们需要安装openssh软件包 span span class token punctuation spa
  • Uni-app 小程序 App 的广告变现之路:激励视频广告

    Intro 激励视频广告 xff0c 是cpm收益最高的广告形式 手机用户观看几十秒视频广告 xff0c 在广告播放完毕后可获得应用开发商提供的奖励 xff0c 而应用开发商则可以从广告平台获取不菲的广告收入 与开屏 信息流等广告变现方式不
  • 数据库查询50道题

    创建四张表 student sc course teacher CREATE DATABASE db 2 CHARSET 61 39 utf8 39 USE db 2 Student Sid Sname Sage Ssex 学生表 DROP
  • 如何使用Python实现图像文字识别OCR

    要使用Python实现图像文字识别OCR xff0c 可以使用以下步骤 xff1a 安装Tesseract OCR引擎 Tesseract是一种开源OCR引擎 xff0c 可以处理多种语言和字体 要使用Python进行OCR xff0c 需
  • C#获取指定日期所在周、月、年的第一天和最后一天

    需求 xff1a 给定一个日期 xff0c 获取日期所在周的周一 周日 xff0c 获取日期所在月的第一天和最后一天 xff0c 获取所在年份的第一天和最后一天 代码如下所示 span class token comment lt summ
  • STM32+W5500网络通信

    目录 一 W5500介绍二 资源分享三 例子程序四 实现应用层modbus httpd协议编程 xff08 一 xff09 modbus xff08 二 xff09 HTTPS 五 总结六 参考链接七 modbus和HTTPS源码 一 W5
  • 服务器部署code-server

    部署code service 思路 1 租用服务器 2 部署code service 3 映射端口 xff0c 修改配置文件 4 让服务一直挂在后台 5 配置C C 43 43 环境 购买服务器 xff0c 部署宝塔面板 这里采用腾讯的云服
  • Arch 中 fcitx5 提示拼音不可用的解决过程

    Arch 中 fcitx5 提示拼音不可用的解决过程 问题描述 xff1a 按照 Fcitx5 ArchWiKi 安装 fcitx5 后不能输入中文 xff0c 提示拼音不可用 查找解决办法 首先查看环境变量设置是否正确 xff1a etc
  • Vue3 setup函数的使用

    全新的 setup 函数 在开始编写 Vue 组件之前 xff0c 需要了解两个全新的前置知识点 xff1a 全新的 setup 函数 xff0c 关系到组件的生命周期和渲染等问题 写 TypeScript 组件离不开的 defineCom
  • Stm32的按键控制流水灯

    对于stm32的设置首先是对时钟进行启动 要求 xff1a key0控制LED0和LED1的亮 key1控制LED0和LED1的亮 kw up控制闪灯 led c span class token macro property span c
  • 头文件之间存在依赖关系该如何包含?

    本文旨在探讨头文件之间存在依赖关系时 xff0c 包含顺序的影响 分两种情况讨论 xff1a 头文件A单方面依赖头文件B xff1a struct h xff1a struct abc int num char ptr def h xff1
  • 单片机入门(利用中断控制流水灯的走向)--适合初学者

    电路图 点击下载 xff08 下载时可能会提醒不安全 xff0c 其实没事 xff0c 本博主是放在自己服务器上面 xff09 代码 span class token macro property span class token dire
  • python实现微信公众号定时消息提醒-手把手教你将代码部署到云端

    这两天微信公众号消息提醒蛮火的 xff0c 我也来蹭一下热度 xff0c 我们的主题是考研倒计时 xff0c 顺便也发一发天气预报 思路 xff1a 获取我们需要的数据 xff0c 比如天气信息 然后去微信公众平台注册一个测试号 xff0c
  • 【章节自测】第三章——顺序程序设计

    第三章 顺序程序设计 学校的老师在上程序设计这门课时 xff0c 给我们每一章指定了一些学习目标 xff0c 用于课前的预习和课后的具体检测复盘 xff0c 因为每一个目标都是具体可测的 xff0c 而只要所有的目标你都能达成 xff0c
  • C语言-进程——信号量

    system V的信号量其实是一个信号量数据 xff0c 一个sysyem V代表的是一个或多个信号量元素 信号量本质上是一个数字 xff0c 用来表征一种资源数量 xff0c 当多个进程或线程争夺这些稀缺资源的时候 xff0c 信号量用来
  • python将包(第三方库)安装到指定目录

    一 在指定目录安装python第三方库 target 61 D software anaconda envs PyTorch Lib 这里的target后面跟的是你python安装环境的lib目录 二 用指定源安装python库 这里用到了
  • Dockerfile详解

    Dockerfile 文章目录 基本结构指令详解FROMRUNLABEL MAINTAINERCOPYADDCMDENTRYPOINTENVARGVOLUMEEXPOSEWORKDIRUSERHEALTHCHECKONBUILD 创建镜像上
  • c++调用yolov4模型进行目标检测-使用opencv4.4.0

    前言 最近刚出的opencv4 4 0也支持了yolov4 xff0c 便尝试用opencv调用yolov4进行检测 xff0c 做个记录 当然 xff0c yolov3 yolov4 tiny等也能调用 xff0c 只需修改加载的cfg和