c++读取yolov5模型进行目标检测(读取摄像头实时监测)

这篇具有很好参考价值的文章主要介绍了c++读取yolov5模型进行目标检测(读取摄像头实时监测)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章介绍

本文是篇基于yolov5模型的一个工程,主要是利用c++将yolov5模型进行调用并测试,从而实现目标检测任务 任务过程中主要重点有两个,第一 版本问题,第二配置问题

一,所需软件及版本

      训练部分 pytorch==1.13.0  opencv==3.4.1   其他的直接pip即可

      c++部署 

       vs2019或者vs2022    

        libtorch-1.13.0

        opencv==3.4.1    链接:https://pan.baidu.com/s/1XPWUNfS7PTFiDkHTG8yvcQ 
提取码:d9g4

        有的可能需要cmake反正我没用    链接:https://pan.baidu.com/s/1-eLo7ecgQg94Mjtw-pQcXw 
提取码:rg0x

二,安装vs

官网地址:
Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本

 上诉链接可能为2017推荐安装 Visual Studio Installer  2019或者2022

环境配置以及任务准备可以借鉴我上一篇文章

libtorch-yolov5部署pytorch版本_该醒醒了~的博客-CSDN博客

好的屁话不多说,正文开始

首先在vs中创建新文件

在源文件中新建一个cpp文件,在头文件新建一个.h 头文件

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

下载yolov5 libtorch

文件链接:https://pan.baidu.com/s/1oIP1btJd10gQddxAHijg7w 
提取码:lntf

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

  • 粘贴 src/YoloV5.cpp 中的代码到上面的 YoloV5.cpp 文件中
  • 粘贴 nclude/YoloV5.h 中的代码到上面的 YoloV5.h 文件中
  • 更改 YoloV5.cpp 中头文件引入方式为 "YoloV5.h
  • c++读取yolov5模型进行目标检测(读取摄像头实时监测)"

改为

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

 在源文件里新建一个main.cpp 文件 此文件是用来调用yolov5的

将代码复制到main.cpp中

这是读取摄像头实时监测的

#include "YoloV5.h"

int main()
{
	// 第二个参数为是否启用 cuda 详细用法可以参考 YoloV5.h 文件
	YoloV5 yolo("C:/Users/hwx/Documents/Github/YoloV5-LibTorch/test/yolov5s.cuda.pt", true);
	// 读取分类标签(我们用的官方的所以这里是 coco 中的分类)
	// 其实这些代码无所谓哪 只是后面预测出来的框没有标签罢了
	std::ifstream f("C:/Users/hwx/Documents/Github/YoloV5-LibTorch/test/coco.txt");
	std::string name = "";
	int i = 0;
	std::map<int, std::string> labels;
	while (std::getline(f, name))
	{
		labels.insert(std::pair<int, std::string>(i, name));
		i++;
	}
	// 用 OpenCV 打开摄像头读取文件(你随便咋样获取图片都OK哪)
	cv::VideoCapture cap = cv::VideoCapture(0);
	// 设置宽高 无所谓多宽多高后面都会通过一个算法转换为固定宽高的
	// 固定宽高值应该是你通过YoloV5训练得到的模型所需要的
	// 传入方式是构造 YoloV5 对象时传入 width 默认值为 640,height 默认值为 640
	cap.set(cv::CAP_PROP_FRAME_WIDTH, 1000);
	cap.set(cv::CAP_PROP_FRAME_HEIGHT, 800);
	cv::Mat frame;
	while (cap.isOpened())
	{
		// 读取一帧
		cap.read(frame);
		if (frame.empty())
		{
			std::cout << "Read frame failed!" << std::endl;
			break;
		}
		// 预测
		// 简单吧,两行代码预测结果就出来了,封装的还可以吧 嘚瑟
		std::vector<torch::Tensor> r = yolo.prediction(frame);
		// 画框根据你自己的项目调用相应的方法,也可以不画框自己处理
		frame = yolo.drawRectangle(frame, r[0], labels);
		// show 图片
		cv::imshow("", frame);
		if (cv::waitKey(1) == 27) break;
	}
	return 0;
}

这个是读取文件夹内所有的图片

#if 0
#include "YOLOv5.h"
#include"Ex.h"
#include<opencv2\opencv.hpp>
#include<io.h>
#include<iostream>

int main()
{
	YoloV5 yolo("D:\\Besktop\\best.torchscript.pt", true);
	// 读取分类标签
	std::ifstream f("D:\\Besktop\\voc.txt");
	std::string name = "";
	int i = 0;

	std::map<int, std::string> labels;
	while (std::getline(f, name))
	{
		labels.insert(std::pair<int, std::string>(i, name));
		std::cout << labels << std::endl;
		i++;
	}
	//cv::Mat frame = cv::imread("D:\\Besktop\\000\\划伤_2023032218553818.bmp");
	string path = "D:\\Besktop\\000\\";
	String dest = "D:\\Besktop\\1\\";
	String savedfilename;
	int len = path.length();
	vector<cv::String> filenames;
	cv::glob(path, filenames);
	for (int i = 0; i < filenames.size(); i++) 
	{
		Mat frame;
		frame = imread(filenames[i], i);
		//frame = 255 - frame;   //对每一张图片取反
		savedfilename = dest + filenames[i].substr(len);
		cout << savedfilename << endl;
		// 预测
		std::vector<torch::Tensor> r = yolo.prediction(frame);
		std::cout << r << std::endl;
		// 画框
		frame = yolo.drawRectangle(frame, r[0], labels);
		//bool is = yolo.existencePrediction(r);
		//std::cout << is << std::endl;
		// show 图片
		//cv::imshow("", frame);
		//imwrite(fileName, frame);
		imwrite(savedfilename, frame);
		cv::waitKey(0);
		//if (cv::waitKey(1) == 27);
		
	}
	return 0;
}
#endif // 0

读取一张图片


#if 1
#include "YoloV5.h"

int main()
{
	YoloV5 yolo("../dataset/best.torchscript.pt", true);
	// 读取分类标签
	std::ifstream f("../dataset/voc.txt");
	std::string name = "";
	int i = 0;
	std::map<int, std::string> labels;
	while (std::getline(f, name))
	{
		labels.insert(std::pair<int, std::string>(i, name));
		i++;
	}
	// 用 OpenCV 打开摄像头读取文件
	//cv::VideoCapture cap = cv::VideoCapture(0);
	//cap.set(cv::CAP_PROP_FRAME_WIDTH, 1000);
	//cap.set(cv::CAP_PROP_FRAME_HEIGHT, 800);
	//cv::Mat frame;
	//while (cap.isOpened())
	//{
	//	// 读取一帧
	//	cap.read(frame);
	//	if (frame.empty())
	//	{
	//		std::cout << "Read frame failed!" << std::endl;
	//		break;
	//	}
		cv::Mat frame = cv::imread("D:\\Besktop\\000\\断栅_2.bmp");
		// 预测
		std::vector<torch::Tensor> r = yolo.prediction(frame);
		std::cout << r << std::endl;
		// 画框处理
		frame = yolo.drawRectangle(frame, r[0], labels);
		// show 图片
		cv::imshow("", frame);
		cv::waitKey(0);
		//if (cv::waitKey(1) == 27) break;
		return 0;
	}
	

#endif // 1

在 VC++目录/包含目录 中添加头文件

 c++读取yolov5模型进行目标检测(读取摄像头实时监测)

在 VC++目录/库目录 中添加 .lib 库 有就添加没有就不添加

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

在 输入/附加依赖项 中添加 lib 库名称 有就添加,没有就不添加

路径在你libtorch和opencv文件中的lib文件夹内

torch.lib
torch_cuda.lib
torch_cuda_cu.lib
torch_cuda_cpp.lib
torch_cpu.lib
c10_cuda.lib
caffe2_nvrtc.lib
c10.lib
kineto.lib
dnnl.lib
fbgemm.lib
asmjit.lib
XNNPACK.lib
cpuinfo.lib
clog.lib
libprotoc.lib
pthreadpool.lib
libprotobuf.lib
libprotobuf-lite.lib
opencv_world341.lib

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

注意   将此libtorch和opencv文件夹下的.dll 文件复制到 你项目文件下的环境内

libtorch   .dll文件打开就可以看到

opencv 的藏得比较深  .......opencv3.4.1\opencv\build\x64\vc15\lib

我的项目文件添加路劲为.......active2\x64\Release

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

 /INCLUDE:"?ignore_this_library_placeholder@@YAHXZ" 

然后修改main函数中的模型路径和下方的标签路径最后运行就好了

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

最后我们再来核对一下

程序中将会有这些文件其中 只需要看main.cpp tesst.cpp YOLOV5.h Yolov5.cpp

这些文件

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

main.cpp在上面有这里就不粘贴了

tesst.cpp

#if 0
#include "YOLOv5.h"
#include"Ex.h"
#include<opencv2\opencv.hpp>
#include<io.h>
#include<iostream>

int main()
{
	YoloV5 yolo("D:\\Besktop\\best.torchscript.pt", true);
	// 读取分类标签
	std::ifstream f("D:\\Besktop\\voc.txt");
	std::string name = "";
	int i = 0;

	std::map<int, std::string> labels;
	while (std::getline(f, name))
	{
		labels.insert(std::pair<int, std::string>(i, name));
		std::cout << labels << std::endl;
		i++;
	}
	//cv::Mat frame = cv::imread("D:\\Besktop\\000\\划伤_2023032218553818.bmp");
	string path = "D:\\Besktop\\000\\";
	String dest = "D:\\Besktop\\1\\";
	String savedfilename;
	int len = path.length();
	vector<cv::String> filenames;
	cv::glob(path, filenames);
	for (int i = 0; i < filenames.size(); i++) 
	{
		Mat frame;
		frame = imread(filenames[i], i);
		//frame = 255 - frame;   //对每一张图片取反
		savedfilename = dest + filenames[i].substr(len);
		cout << savedfilename << endl;
		// 预测
		std::vector<torch::Tensor> r = yolo.prediction(frame);
		std::cout << r << std::endl;
		// 画框
		frame = yolo.drawRectangle(frame, r[0], labels);
		//bool is = yolo.existencePrediction(r);
		//std::cout << is << std::endl;
		// show 图片
		//cv::imshow("", frame);
		//imwrite(fileName, frame);
		imwrite(savedfilename, frame);
		cv::waitKey(0);
		//if (cv::waitKey(1) == 27);
		
	}
	return 0;
}
#endif // 0

yolov5.h

#pragma once
#include <torch/torch.h>
#include <torch/script.h>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <ctime>
/**
 * ImageResizeData 图片处理过后保存图片的数据结构
 */
class ImageResizeData
{
public:
	// 添加处理过后的图片
	void setImg(cv::Mat img);
	// 获取处理过后的图片
	cv::Mat getImg();
	// 当原始图片宽高比大于处理过后图片宽高比时此函数返回 true
	bool isW();
	// 当原始图片高宽比大于处理过后图片高宽比时此函数返回 true
	bool isH();
	// 添加处理之后图片的宽
	void setWidth(int width);
	// 获取处理之后图片的宽
	int getWidth();
	// 添加处理之后图片的高
	void setHeight(int height);
	// 获取处理之后图片的高
	int getHeight();
	// 添加原始图片的宽
	void setW(int w);
	// 获取原始图片的宽
	int getW();
	// 添加原始图片的高
	void setH(int h);
	// 获取原始图片的高
	int getH();
	// 添加从原始图片到处理过后图片所添加黑边大小
	void setBorder(int border);
	// 获取从原始图片到处理过后图片所添加黑边大小
	int getBorder();
private:
	// 处理过后图片高
	int height;
	// 处理过后图片宽
	int width;
	// 原始图片宽
	int w;
	// 原始图片高
	int h;
	// 从原始图片到处理图片所添加的黑边大小
	int border;
	// 处理过后的图片
	cv::Mat img;
};

/**
 * YoloV5 的实现类
 */
class YoloV5
{
public:
	/**
	 * 构造函数
	 * @param ptFile yoloV5 pt文件路径
	 * @param isCuda 是否使用 cuda 默认不起用
	 * @param height yoloV5 训练时图片的高
	 * @param width yoloV5 训练时图片的宽
	 * @param confThres 非极大值抑制中的 scoreThresh
	 * @param iouThres 非极大值抑制中的 iouThresh
	 */
	YoloV5(std::string ptFile, bool isCuda = false, bool isHalf = false, int height = 640, int width = 640, float confThres = 0.25, float iouThres = 0.45);
	/**
	 * 预测函数
	 * @param data 语言预测的数据格式 (batch, rgb, height, width)
	 */
	std::vector<torch::Tensor> prediction(torch::Tensor data);
	/**
	 * 预测函数
	 * @param filePath 需要预测的图片路径
	 */
	std::vector<torch::Tensor> prediction(std::string filePath);
	/**
	 * 预测函数
	 * @param img 需要预测的图片
	 */
	std::vector<torch::Tensor> prediction(cv::Mat img);
	/**
	 * 预测函数
	 * @param imgs 需要预测的图片集合
	 */
	std::vector<torch::Tensor> prediction(std::vector <cv::Mat> imgs);
	/**
	 * 改变图片大小的函数
	 * @param img 原始图片
	 * @param height 要处理成的图片的高
	 * @param width 要处理成的图片的宽
	 * @return 封装好的处理过后图片数据结构
	 */
	static ImageResizeData resize(cv::Mat img, int height, int width);
	/**
	 * 改变图片大小的函数
	 * @param img 原始图片
	 * @return 封装好的处理过后图片数据结构
	 */
	ImageResizeData resize(cv::Mat img);
	/**
	 * 改变图片大小的函数
	 * @param imgs 原始图片集合
	 * @param height 要处理成的图片的高
	 * @param width 要处理成的图片的宽
	 * @return 封装好的处理过后图片数据结构
	 */
	static std::vector<ImageResizeData> resize(std::vector <cv::Mat> imgs, int height, int width);
	/**
	 * 改变图片大小的函数
	 * @param imgs 原始图片集合
	 * @return 封装好的处理过后图片数据结构
	 */
	std::vector<ImageResizeData> resize(std::vector <cv::Mat> imgs);
	/**
	 * 根据输出结果在给定图片中画出框
	 * @param imgs 原始图片集合
	 * @param rectangles 通过预测函数处理好的结果
	 * @param labels 类别标签
	 * @param thickness 线宽
	 * @return 画好框的图片
	 */
	std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, std::string> labels, int thickness = 2);
	/**
	 * 根据输出结果在给定图片中画出框
	 * @param imgs 原始图片集合
	 * @param rectangles 通过预测函数处理好的结果
	 * @param thickness 线宽
	 * @return 画好框的图片
	 */
	std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, int thickness = 2);
	/**
	 * 根据输出结果在给定图片中画出框
	 * @param imgs 原始图片集合
	 * @param rectangles 通过预测函数处理好的结果
	 * @param colors 每种类型对应颜色
	 * @param labels 类别标签
	 * @return 画好框的图片
	 */
	std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness = 2);
	/**
	 * 根据输出结果在给定图片中画出框
	 * @param img 原始图片
	 * @param rectangle 通过预测函数处理好的结果
	 * @param thickness 线宽
	 * @return 画好框的图片
	 */
	cv::Mat	drawRectangle(cv::Mat img, torch::Tensor rectangle, int thickness = 2);
	/**
	 * 根据输出结果在给定图片中画出框
	 * @param img 原始图片
	 * @param rectangle 通过预测函数处理好的结果
	 * @param labels 类别标签
	 * @param thickness 线宽
	 * @return 画好框的图片
	 */
	cv::Mat	drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, std::string> labels, int thickness = 2);
	/**
	 * 根据输出结果在给定图片中画出框
	 * @param img 原始图片
	 * @param rectangle 通过预测函数处理好的结果
	 * @param colos 每种类型对应颜色
	 * @param labels 类别标签
	 * @param thickness 线宽
	 * @return 画好框的图片
	 */
	cv::Mat	drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness = 2);
	/**
	 * 用于判断给定数据是否存在预测
	 * @param clazz 通过预测函数处理好的结果
	 * @return 如果图片中存在给定某一种分类返回 true
	 */
	bool existencePrediction(torch::Tensor clazz);
	/**
	 * 用于判断给定数据是否存在预测
	 * @param classs 通过预测函数处理好的结果
	 * @return 如果图片集合中存在给定某一种分类返回 true
	 */
	bool existencePrediction(std::vector<torch::Tensor> classs);

private:
	// 是否启用 cuda
	bool isCuda;
	// 是否使用半精度
	bool isHalf;
	// 非极大值抑制中的第一步数据清理
	float confThres;
	// 非极大值抑制中 iou
	float iouThres;
	// 模型所需要的图片的高
	float height;
	// 模型所需要的图片的宽
	float width;
	// 画框颜色 map
	std::map<int, cv::Scalar> mainColors;
	// 模型
	torch::jit::script::Module model;
	// 随机获取一种颜色
	cv::Scalar getRandScalar();
	// 图片通道转换为 rgb
	cv::Mat img2RGB(cv::Mat img);
	// 图片变为 Tensor
	torch::Tensor img2Tensor(cv::Mat img);
	// (center_x center_y w h) to (left, top, right, bottom)
	torch::Tensor xywh2xyxy(torch::Tensor x);
	// 非极大值抑制算法
	torch::Tensor nms(torch::Tensor bboxes, torch::Tensor scores, float thresh);
	// 预测出来的框根据原始图片还原算法
	std::vector<torch::Tensor> sizeOriginal(std::vector<torch::Tensor> result, std::vector<ImageResizeData> imgRDs);
	// 非极大值抑制算法整体
	std::vector<torch::Tensor> non_max_suppression(torch::Tensor preds, float confThres = 0.25, float iouThres = 0.45);
};

 yolov5.cpp

#include "YoloV5.h"

YoloV5::YoloV5(std::string ptFile, bool isCuda, bool isHalf, int height, int width, float confThres, float iouThres)
{
	model = torch::jit::load(ptFile);
	if (isCuda)
	{
		model.to(torch::kCUDA);
	}
	if (isHalf)
	{
		model.to(torch::kHalf);
	}
	this->height = height;
	this->width = width;
	this->isCuda = isCuda;
	this->iouThres = iouThres;
	this->confThres = confThres;
	this->isHalf = isHalf;
	model.eval();
	unsigned seed = time(0);
	std::srand(seed);
}

std::vector<torch::Tensor> YoloV5::non_max_suppression(torch::Tensor prediction, float confThres, float iouThres)
{
	torch::Tensor xc = prediction.select(2, 4) > confThres;
	int maxWh = 4096;
	int maxNms = 30000;
	std::vector<torch::Tensor> output;
	for (int i = 0; i < prediction.size(0); i++)
	{
		output.push_back(torch::zeros({ 0, 6 }));
	}
	for (int i = 0; i < prediction.size(0); i++)
	{
		torch::Tensor x = prediction[i];
		x = x.index_select(0, torch::nonzero(xc[i]).select(1, 0));
		if (x.size(0) == 0) continue;

		x.slice(1, 5, x.size(1)).mul_(x.slice(1, 4, 5));
		torch::Tensor box = xywh2xyxy(x.slice(1, 0, 4));
		std::tuple<torch::Tensor, torch::Tensor> max_tuple = torch::max(x.slice(1, 5, x.size(1)), 1, true);
		x = torch::cat({ box, std::get<0>(max_tuple), std::get<1>(max_tuple) }, 1);
		x = x.index_select(0, torch::nonzero(std::get<0>(max_tuple) > confThres).select(1, 0));
		int n = x.size(0);
		if (n == 0)
		{
			continue;
		}
		else if (n > maxNms)
		{
			x = x.index_select(0, x.select(1, 4).argsort(0, true).slice(0, 0, maxNms));
		}
		torch::Tensor c = x.slice(1, 5, 6) * maxWh;
		torch::Tensor boxes = x.slice(1, 0, 4) + c, scores = x.select(1, 4);
		torch::Tensor ix = nms(boxes, scores, iouThres).to(x.device());
		output[i] = x.index_select(0, ix).cpu();
	}
	return output;
}

cv::Scalar YoloV5::getRandScalar()
{
	return cv::Scalar(std::rand() % 256, std::rand() % 256, std::rand() % 256);
}

cv::Mat YoloV5::img2RGB(cv::Mat img)
{
	int imgC = img.channels();
	if (imgC == 1)
	{
		cv::cvtColor(img, img, cv::COLOR_GRAY2RGB);
	}
	else
	{
		cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
	}
	return img;
}

torch::Tensor YoloV5::img2Tensor(cv::Mat img)
{
	torch::Tensor data = torch::from_blob(img.data, { (int)height, (int)width, 3 }, torch::kByte);
	data = data.permute({ 2, 0, 1 });
	data = data.toType(torch::kFloat);
	data = data.div(255);
	data = data.unsqueeze(0);
	return data;
}

torch::Tensor YoloV5::xywh2xyxy(torch::Tensor x)
{
	torch::Tensor y = x.clone();
	y.select(1, 0) = x.select(1, 0) - x.select(1, 2) / 2;
	y.select(1, 1) = x.select(1, 1) - x.select(1, 3) / 2;
	y.select(1, 2) = x.select(1, 0) + x.select(1, 2) / 2;
	y.select(1, 3) = x.select(1, 1) + x.select(1, 3) / 2;
	return y;
}

torch::Tensor YoloV5::nms(torch::Tensor bboxes, torch::Tensor scores, float thresh)
{
	auto x1 = bboxes.select(1, 0);
	auto y1 = bboxes.select(1, 1);
	auto x2 = bboxes.select(1, 2);
	auto y2 = bboxes.select(1, 3);
	auto areas = (x2 - x1) * (y2 - y1);
	auto tuple_sorted = scores.sort(0, true);
	auto order = std::get<1>(tuple_sorted);

	std::vector<int> keep;
	while (order.numel() > 0)
	{
		if (order.numel() == 1)
		{
			auto i = order.item();
			keep.push_back(i.toInt());
			break;
		}
		else
		{
			auto i = order[0].item();
			keep.push_back(i.toInt());
		}

		auto order_mask = order.narrow(0, 1, order.size(-1) - 1);

		auto xx1 = x1.index({ order_mask }).clamp(x1[keep.back()].item().toFloat(), 1e10);
		auto yy1 = y1.index({ order_mask }).clamp(y1[keep.back()].item().toFloat(), 1e10);
		auto xx2 = x2.index({ order_mask }).clamp(0, x2[keep.back()].item().toFloat());
		auto yy2 = y2.index({ order_mask }).clamp(0, y2[keep.back()].item().toFloat());
		auto inter = (xx2 - xx1).clamp(0, 1e10) * (yy2 - yy1).clamp(0, 1e10);

		auto iou = inter / (areas[keep.back()] + areas.index({ order.narrow(0,1,order.size(-1) - 1) }) - inter);
		auto idx = (iou <= thresh).nonzero().squeeze();
		if (idx.numel() == 0)
		{
			break;
		}
		order = order.index({ idx + 1 });
	}
	return torch::tensor(keep);
}

std::vector<torch::Tensor> YoloV5::sizeOriginal(std::vector<torch::Tensor> result, std::vector<ImageResizeData> imgRDs)
{
	std::vector<torch::Tensor> resultOrg;
	for (int i = 0; i < result.size(); i++)
	{

		torch::Tensor data = result[i];
		ImageResizeData imgRD = imgRDs[i];
		for (int j = 0; j < data.size(0); j++)
		{
			torch::Tensor tensor = data.select(0, j);
			// (left, top, right, bottom)
			if (imgRD.isW())
			{
				tensor[1] -= imgRD.getBorder();
				tensor[3] -= imgRD.getBorder();
				tensor[0] *= (float)imgRD.getW() / (float)imgRD.getWidth();
				tensor[2] *= (float)imgRD.getW() / (float)imgRD.getWidth();
				tensor[1] *= (float)imgRD.getH() / (float)(imgRD.getHeight() - 2 * imgRD.getBorder());
				tensor[3] *= (float)imgRD.getH() / (float)(imgRD.getHeight() - 2 * imgRD.getBorder());
			}
			else
			{
				tensor[0] -= imgRD.getBorder();
				tensor[2] -= imgRD.getBorder();
				tensor[1] *= (float)imgRD.getH() / (float)imgRD.getHeight();
				tensor[3] *= (float)imgRD.getH() / (float)imgRD.getHeight();
				tensor[0] *= (float)imgRD.getW() / (float)(imgRD.getWidth() - 2 * imgRD.getBorder());
				tensor[2] *= (float)imgRD.getW() / (float)(imgRD.getWidth() - 2 * imgRD.getBorder());
			}
			// 加了黑边之后预测结果可能在黑边上,就会造成结果为负数
			for (int k = 0; k < 4; k++)
			{
				if (tensor[k].item().toFloat() < 0)
				{
					tensor[k] = 0;
				}
			}
		}

		resultOrg.push_back(data);
	}
	return resultOrg;
}

std::vector<torch::Tensor> YoloV5::prediction(torch::Tensor data)
{
	if (!data.is_cuda() && this->isCuda)
	{
		data = data.cuda();
	}
	if (data.is_cuda() && !this->isCuda)
	{
		data = data.cpu();
	}
	if (this->isHalf)
	{
		data = data.to(torch::kHalf);
	}
	torch::Tensor pred = model.forward({ data }).toTuple()->elements()[0].toTensor();
	return non_max_suppression(pred, confThres, iouThres);
}

std::vector<torch::Tensor> YoloV5::prediction(std::string filePath)
{
	cv::Mat img = cv::imread(filePath);
	return prediction(img);
}

std::vector<torch::Tensor> YoloV5::prediction(cv::Mat img)
{
	ImageResizeData imgRD = resize(img);
	cv::Mat reImg = img2RGB(imgRD.getImg());
	torch::Tensor data = img2Tensor(reImg);
	std::vector<torch::Tensor> result = prediction(data);
	std::vector<ImageResizeData> imgRDs;
	imgRDs.push_back(imgRD);
	return sizeOriginal(result, imgRDs);
}

std::vector<torch::Tensor> YoloV5::prediction(std::vector<cv::Mat> imgs)
{
	std::vector<ImageResizeData> imageRDs;
	std::vector<torch::Tensor> datas;
	for (int i = 0; i < imgs.size(); i++)
	{
		ImageResizeData imgRD = resize(imgs[i]);
		imageRDs.push_back(imgRD);
		cv::Mat img = img2RGB(imgRD.getImg());
		datas.push_back(img2Tensor(img));
	}
	torch::Tensor data = torch::cat(datas, 0);
	std::vector<torch::Tensor> result = prediction(data);
	return sizeOriginal(result, imageRDs);
}

ImageResizeData YoloV5::resize(cv::Mat img, int height, int width)
{
	ImageResizeData imgResizeData;
	int w = img.cols, h = img.rows;
	imgResizeData.setH(h);
	imgResizeData.setW(w);
	imgResizeData.setHeight(height);
	imgResizeData.setWidth(width);
	bool isW = (float)w / (float)h > (float)width / (float)height;

	cv::resize(img, img, cv::Size(
		isW ? width : (int)((float)height / (float)h * w),
		isW ? (int)((float)width / (float)w * h) : height));

	w = img.cols, h = img.rows;
	if (isW)
	{
		imgResizeData.setBorder((height - h) / 2);
		cv::copyMakeBorder(img, img, (height - h) / 2, height - h - (height - h) / 2, 0, 0, cv::BORDER_CONSTANT);
	}
	else
	{
		imgResizeData.setBorder((width - w) / 2);
		cv::copyMakeBorder(img, img, 0, 0, (width - w) / 2, width - w - (width - w) / 2, cv::BORDER_CONSTANT);
	}
	imgResizeData.setImg(img);
	return imgResizeData;
}

ImageResizeData YoloV5::resize(cv::Mat img)
{
	return YoloV5::resize(img, height, width);
}

std::vector<ImageResizeData> YoloV5::resize(std::vector<cv::Mat> imgs, int height, int width)
{
	std::vector<ImageResizeData> imgRDs;
	for (int i = 0; i < imgs.size(); i++)
	{
		imgRDs.push_back(YoloV5::resize(imgs[i], height, width));
	}
	return imgRDs;
}

std::vector<ImageResizeData> YoloV5::resize(std::vector<cv::Mat> imgs)
{
	return YoloV5::resize(imgs, height, width);
}

std::vector<cv::Mat> YoloV5::drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, std::string> labels, int thickness)
{
	std::map<int, cv::Scalar> colors;
	return drawRectangle(imgs, rectangles, colors, labels, thickness);
}

std::vector<cv::Mat> YoloV5::drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, int thickness)
{
	std::map<int, cv::Scalar> colors;
	std::map<int, std::string> labels;
	return drawRectangle(imgs, rectangles, colors, labels, thickness);
}

std::vector<cv::Mat> YoloV5::drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness)
{
	std::vector<cv::Mat> results;
	for (int i = 0; i < imgs.size(); i++)
	{
		results.push_back(drawRectangle(imgs[i], rectangles[i], colors, labels, thickness));
	}
	return results;
}

cv::Mat YoloV5::drawRectangle(cv::Mat img, torch::Tensor rectangle, int thickness)
{
	std::map<int, cv::Scalar> colors;
	std::map<int, std::string> labels;
	return drawRectangle(img, rectangle, colors, labels, thickness);
}

cv::Mat YoloV5::drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, std::string> labels, int thickness)
{
	std::map<int, cv::Scalar> colors;
	return drawRectangle(img, rectangle, colors, labels, thickness);
}

cv::Mat YoloV5::drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness)
{
	std::map<int, cv::Scalar>::iterator it;
	std::map<int, std::string>::iterator labelIt;
	for (int i = 0; i < rectangle.size(0); i++)
	{
		int clazz = rectangle[i][5].item().toInt();
		it = colors.find(clazz);
		cv::Scalar color = NULL;
		if (it == colors.end())
		{
			it = mainColors.find(clazz);
			if (it == mainColors.end())
			{
				color = getRandScalar();
				mainColors.insert(std::pair<int, cv::Scalar>(clazz, color));
			}
			else
			{
				color = it->second;
			}
		}
		else
		{
			color = it->second;
		}
		cv::rectangle(img, cv::Point(rectangle[i][0].item().toInt(), rectangle[i][1].item().toInt()), cv::Point(rectangle[i][2].item().toInt(), rectangle[i][3].item().toInt()), color, thickness);
		labelIt = labels.find(clazz);

		std::ostringstream oss;

		if (labelIt != labels.end())
		{
			oss << labelIt->second << " ";
		}

		oss << rectangle[i][4].item().toFloat();
		std::string label = oss.str();

		cv::putText(img, label, cv::Point(rectangle[i][0].item().toInt(), rectangle[i][1].item().toInt()), cv::FONT_HERSHEY_PLAIN, 1, color, thickness);
	}
	return img;
}

bool YoloV5::existencePrediction(torch::Tensor clazz)
{
	return clazz.size(0) > 0 ? true : false;
}

bool YoloV5::existencePrediction(std::vector<torch::Tensor> classs)
{
	for (int i = 0; i < classs.size(); i++)
	{
		if (existencePrediction(classs[i]))
		{
			return true;
		}
	}
	return false;
}


void ImageResizeData::setImg(cv::Mat img)
{
	this->img = img;
}

cv::Mat ImageResizeData::getImg()
{
	return img;
}

bool ImageResizeData::isW()
{
	return (float)w / (float)h > (float)width / (float)height;
}

bool ImageResizeData::isH()
{
	return (float)h / (float)w > (float)height / (float)width;
}

void ImageResizeData::setWidth(int width)
{
	this->width = width;
}

int ImageResizeData::getWidth()
{
	return width;
}

void ImageResizeData::setHeight(int height)
{
	this->height = height;
}

int ImageResizeData::getHeight()
{
	return height;
}

void ImageResizeData::setW(int w)
{
	this->w = w;
}

int ImageResizeData::getW()
{
	return w;
}

void ImageResizeData::setH(int h)
{
	this->h = h;
}

int ImageResizeData::getH()
{
	return h;
}

void ImageResizeData::setBorder(int border)
{
	this->border = border;
}

int ImageResizeData::getBorder()
{
	return border;
}

 这个效果是读取摄像图进行试试检测博文中有将摄像头替换为图片进行检测的案例

c++读取yolov5模型进行目标检测(读取摄像头实时监测)

 文章来源地址https://www.toymoban.com/news/detail-469191.html

看得懂就看,看不懂的评论区问我

到了这里,关于c++读取yolov5模型进行目标检测(读取摄像头实时监测)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Opencv C++实现yolov5部署onnx模型完成目标检测

    头文件 命名空间 结构体 Net_config 里面存了三个阈值和模型地址,其中 置信度 ,顾名思义,看检测出来的物体的精准度。以测量值为中心,在一定范围内,真值出现在该范围内的几率。 endsWith()函数 判断sub是不是s的子串 anchors_640图像接收数组 根据图像大小,选择相应长度的

    2024年02月13日
    浏览(41)
  • 利用yolov5进行目标检测,并将检测到的目标裁剪出来

    写在前面:关于yolov5的调试运行在这里不做过多赘述,有关yolov5的调试运行请看: https://www.bilibili.com/video/BV1tf4y1t7ru/spm_id_from=333.999.0.0vd_source=043dc71f3eaf6a0ccb6dada9dbd8be37 本文章主要讲解的是裁剪。 需求:识别图片中的人物并将其裁剪出来 如果只需识别人物的话,那么只需在y

    2024年02月02日
    浏览(43)
  • 记录使用yolov5进行旋转目标的检测

    由于实习公司需要使用到旋转目标的检测,所以这几天学习了相关知识,并找了许多资料,饶了许多的弯路。下面记录下项目的整个实现过程。 我参考的是以下几位博主: DOTAv2遥感图像旋转目标检测竞赛经验分享(Swin Transformer + Anchor free/based方案) - 知乎 小鸡炖技术的个人

    2024年02月02日
    浏览(45)
  • Yolov5同时进行目标检测和分割分割

    基于yolov5(v6.0分支)的多任务检测和分割模型。 之前很早就萌生idea在yolov5基础上添加一个分割头用于语义分割,近期正好也有论文YLOLOP是这么做的. 这里基于yolov5最新分支修改,主要改动如下: 1 . 解耦头:实验在小数据集上有一定效果(map 1%+ ),大数据集上提升不明显; 2.

    2024年02月05日
    浏览(44)
  • 【目标检测】yolov5模型详解

    yolov5于2020年由glenn-jocher首次提出,直至今日yolov5仍然在不断进行升级迭代。 Yolov5有YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x四个版本。文件中,这几个模型的结构基本一样,不同的是depth_multiple模型深度和width_multiple模型宽度这两个参数。 yolov5主要分为以下几部分: Input:输入 Backbone:

    2024年02月07日
    浏览(52)
  • 【目标检测】YOLOv5:模型构建解析

    最近在看一些目标检测的最新论文和代码,大多数都是在YOLOv5的基础上进行魔改。 改的最多的基本是原版本的网络结构,这篇博文就从源码角度来解析YOLOv5中,模型是如何构建出来的。 本文使用的是YOLOv5-5.0版本。 在YOLOv5中,模型结构基本是写在了 .yaml 中,5.0版本的YOLOv5共

    2024年02月06日
    浏览(90)
  • yolov5模型(.pt)在RK3588(S)上的部署(实时摄像头检测)

    github仓库 所需: 安装了Ubuntu20系统的RK3588 安装了Ubuntu18的电脑或者虚拟机 一、yolov5 PT模型获取 Anaconda教程 YOLOv5教程 经过上面两个教程之后,你应该获取了自己的 best.pt 文件 二、PT模型转onnx模型 将 models/yolo.py 文件中的 class 类下的 forward 函数由: 改为: 将 export.py 文件中的

    2024年02月06日
    浏览(48)
  • YOLOv5+BiSeNet——同时进行目标检测和语义分割

    在Gayhub上看到个项目,有人在YOLOv5的基础上,新增了一个分割头,把BiSeNet语义分割算法加入到了目标检测中,使其能够同时进行目标检测和语义分割。 项目地址:https://github.com/TomMao23/multiyolov5 先看我使用原作者提供的模型,复刻出来的效果: (本来想放视频的,不过传了两

    2024年02月07日
    浏览(46)
  • yolov5目标检测多线程C++部署

    下面的代码搭建了简单的一个生产者-消费者模型,在capture()函数中进行入队操作,infer()函数中进行出队操作,为了模拟采图-推理流程,在函数中调用Sleep()函数延时。 输出结果: 现在我们把capture函数中的Sleep(1000)改成Sleep(500)来模拟生产者加速生产,再次执行程序,则输出:

    2024年02月13日
    浏览(44)
  • 目标检测 YOLOv5 预训练模型下载方法

    目标检测 YOLOv5 预训练模型下载方法 flyfish https://github.com/ultralytics/yolov5 https://github.com/ultralytics/yolov5/releases 可以选择自己需要的版本和不同任务类型的模型 后缀名是pt

    2024年02月08日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包