国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

這篇具有很好參考價(jià)值的文章主要介紹了c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

文章介紹

本文是篇基于yolov5模型的一個(gè)工程,主要是利用c++將yolov5模型進(jìn)行調(diào)用并測試,從而實(shí)現(xiàn)目標(biāo)檢測任務(wù) 任務(wù)過程中主要重點(diǎn)有兩個(gè),第一 版本問題,第二配置問題

一,所需軟件及版本

? ? ? 訓(xùn)練部分 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

官網(wǎng)地址:
Visual Studio 較舊的下載 - 2019、2017、2015 和以前的版本

?上訴鏈接可能為2017推薦安裝 Visual Studio Installer? 2019或者2022

環(huán)境配置以及任務(wù)準(zhǔn)備可以借鑒我上一篇文章

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

好的屁話不多說,正文開始

首先在vs中創(chuàng)建新文件

在源文件中新建一個(gè)cpp文件,在頭文件新建一個(gè).h 頭文件

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

下載yolov5 libtorch

文件鏈接:https://pan.baidu.com/s/1oIP1btJd10gQddxAHijg7w?
提取碼:lntf

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

  • 粘貼 src/YoloV5.cpp 中的代碼到上面的 YoloV5.cpp 文件中
  • 粘貼 nclude/YoloV5.h 中的代碼到上面的 YoloV5.h 文件中
  • 更改 YoloV5.cpp 中頭文件引入方式為 "YoloV5.h
  • c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)"

改為

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

?在源文件里新建一個(gè)main.cpp 文件 此文件是用來調(diào)用yolov5的

將代碼復(fù)制到main.cpp中

這是讀取攝像頭實(shí)時(shí)監(jiān)測的

#include "YoloV5.h"

int main()
{
	// 第二個(gè)參數(shù)為是否啟用 cuda 詳細(xì)用法可以參考 YoloV5.h 文件
	YoloV5 yolo("C:/Users/hwx/Documents/Github/YoloV5-LibTorch/test/yolov5s.cuda.pt", true);
	// 讀取分類標(biāo)簽(我們用的官方的所以這里是 coco 中的分類)
	// 其實(shí)這些代碼無所謂哪 只是后面預(yù)測出來的框沒有標(biāo)簽罷了
	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);
	// 設(shè)置寬高 無所謂多寬多高后面都會通過一個(gè)算法轉(zhuǎn)換為固定寬高的
	// 固定寬高值應(yīng)該是你通過YoloV5訓(xùn)練得到的模型所需要的
	// 傳入方式是構(gòu)造 YoloV5 對象時(shí)傳入 width 默認(rèn)值為 640,height 默認(rèn)值為 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;
		}
		// 預(yù)測
		// 簡單吧,兩行代碼預(yù)測結(jié)果就出來了,封裝的還可以吧 嘚瑟
		std::vector<torch::Tensor> r = yolo.prediction(frame);
		// 畫框根據(jù)你自己的項(xiàng)目調(diào)用相應(yīng)的方法,也可以不畫框自己處理
		frame = yolo.drawRectangle(frame, r[0], labels);
		// show 圖片
		cv::imshow("", frame);
		if (cv::waitKey(1) == 27) break;
	}
	return 0;
}

這個(gè)是讀取文件夾內(nèi)所有的圖片

#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);
	// 讀取分類標(biāo)簽
	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;
		// 預(yù)測
		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);
	// 讀取分類標(biāo)簽
	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");
		// 預(yù)測
		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模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

在 VC++目錄/庫目錄 中添加 .lib 庫 有就添加沒有就不添加

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

在 輸入/附加依賴項(xiàng) 中添加 lib 庫名稱 有就添加,沒有就不添加

路徑在你libtorch和opencv文件中的lib文件夾內(nèi)

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模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

注意? ?將此libtorch和opencv文件夾下的.dll?文件復(fù)制到 你項(xiàng)目文件下的環(huán)境內(nèi)

libtorch? ?.dll文件打開就可以看到

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

我的項(xiàng)目文件添加路勁為.......active2\x64\Release

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

?/INCLUDE:"?ignore_this_library_placeholder@@YAHXZ"?

然后修改main函數(shù)中的模型路徑和下方的標(biāo)簽路徑最后運(yùn)行就好了

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

最后我們再來核對一下

程序中將會有這些文件其中 只需要看main.cpp tesst.cpp YOLOV5.h Yolov5.cpp

這些文件

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

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);
	// 讀取分類標(biāo)簽
	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;
		// 預(yù)測
		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 圖片處理過后保存圖片的數(shù)據(jù)結(jié)構(gòu)
 */
class ImageResizeData
{
public:
	// 添加處理過后的圖片
	void setImg(cv::Mat img);
	// 獲取處理過后的圖片
	cv::Mat getImg();
	// 當(dāng)原始圖片寬高比大于處理過后圖片寬高比時(shí)此函數(shù)返回 true
	bool isW();
	// 當(dāng)原始圖片高寬比大于處理過后圖片高寬比時(shí)此函數(shù)返回 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 的實(shí)現(xiàn)類
 */
class YoloV5
{
public:
	/**
	 * 構(gòu)造函數(shù)
	 * @param ptFile yoloV5 pt文件路徑
	 * @param isCuda 是否使用 cuda 默認(rèn)不起用
	 * @param height yoloV5 訓(xùn)練時(shí)圖片的高
	 * @param width yoloV5 訓(xùn)練時(shí)圖片的寬
	 * @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);
	/**
	 * 預(yù)測函數(shù)
	 * @param data 語言預(yù)測的數(shù)據(jù)格式 (batch, rgb, height, width)
	 */
	std::vector<torch::Tensor> prediction(torch::Tensor data);
	/**
	 * 預(yù)測函數(shù)
	 * @param filePath 需要預(yù)測的圖片路徑
	 */
	std::vector<torch::Tensor> prediction(std::string filePath);
	/**
	 * 預(yù)測函數(shù)
	 * @param img 需要預(yù)測的圖片
	 */
	std::vector<torch::Tensor> prediction(cv::Mat img);
	/**
	 * 預(yù)測函數(shù)
	 * @param imgs 需要預(yù)測的圖片集合
	 */
	std::vector<torch::Tensor> prediction(std::vector <cv::Mat> imgs);
	/**
	 * 改變圖片大小的函數(shù)
	 * @param img 原始圖片
	 * @param height 要處理成的圖片的高
	 * @param width 要處理成的圖片的寬
	 * @return 封裝好的處理過后圖片數(shù)據(jù)結(jié)構(gòu)
	 */
	static ImageResizeData resize(cv::Mat img, int height, int width);
	/**
	 * 改變圖片大小的函數(shù)
	 * @param img 原始圖片
	 * @return 封裝好的處理過后圖片數(shù)據(jù)結(jié)構(gòu)
	 */
	ImageResizeData resize(cv::Mat img);
	/**
	 * 改變圖片大小的函數(shù)
	 * @param imgs 原始圖片集合
	 * @param height 要處理成的圖片的高
	 * @param width 要處理成的圖片的寬
	 * @return 封裝好的處理過后圖片數(shù)據(jù)結(jié)構(gòu)
	 */
	static std::vector<ImageResizeData> resize(std::vector <cv::Mat> imgs, int height, int width);
	/**
	 * 改變圖片大小的函數(shù)
	 * @param imgs 原始圖片集合
	 * @return 封裝好的處理過后圖片數(shù)據(jù)結(jié)構(gòu)
	 */
	std::vector<ImageResizeData> resize(std::vector <cv::Mat> imgs);
	/**
	 * 根據(jù)輸出結(jié)果在給定圖片中畫出框
	 * @param imgs 原始圖片集合
	 * @param rectangles 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @param labels 類別標(biāo)簽
	 * @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);
	/**
	 * 根據(jù)輸出結(jié)果在給定圖片中畫出框
	 * @param imgs 原始圖片集合
	 * @param rectangles 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @param thickness 線寬
	 * @return 畫好框的圖片
	 */
	std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, int thickness = 2);
	/**
	 * 根據(jù)輸出結(jié)果在給定圖片中畫出框
	 * @param imgs 原始圖片集合
	 * @param rectangles 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @param colors 每種類型對應(yīng)顏色
	 * @param labels 類別標(biāo)簽
	 * @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);
	/**
	 * 根據(jù)輸出結(jié)果在給定圖片中畫出框
	 * @param img 原始圖片
	 * @param rectangle 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @param thickness 線寬
	 * @return 畫好框的圖片
	 */
	cv::Mat	drawRectangle(cv::Mat img, torch::Tensor rectangle, int thickness = 2);
	/**
	 * 根據(jù)輸出結(jié)果在給定圖片中畫出框
	 * @param img 原始圖片
	 * @param rectangle 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @param labels 類別標(biāo)簽
	 * @param thickness 線寬
	 * @return 畫好框的圖片
	 */
	cv::Mat	drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, std::string> labels, int thickness = 2);
	/**
	 * 根據(jù)輸出結(jié)果在給定圖片中畫出框
	 * @param img 原始圖片
	 * @param rectangle 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @param colos 每種類型對應(yīng)顏色
	 * @param labels 類別標(biāo)簽
	 * @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);
	/**
	 * 用于判斷給定數(shù)據(jù)是否存在預(yù)測
	 * @param clazz 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @return 如果圖片中存在給定某一種分類返回 true
	 */
	bool existencePrediction(torch::Tensor clazz);
	/**
	 * 用于判斷給定數(shù)據(jù)是否存在預(yù)測
	 * @param classs 通過預(yù)測函數(shù)處理好的結(jié)果
	 * @return 如果圖片集合中存在給定某一種分類返回 true
	 */
	bool existencePrediction(std::vector<torch::Tensor> classs);

private:
	// 是否啟用 cuda
	bool isCuda;
	// 是否使用半精度
	bool isHalf;
	// 非極大值抑制中的第一步數(shù)據(jù)清理
	float confThres;
	// 非極大值抑制中 iou
	float iouThres;
	// 模型所需要的圖片的高
	float height;
	// 模型所需要的圖片的寬
	float width;
	// 畫框顏色 map
	std::map<int, cv::Scalar> mainColors;
	// 模型
	torch::jit::script::Module model;
	// 隨機(jī)獲取一種顏色
	cv::Scalar getRandScalar();
	// 圖片通道轉(zhuǎn)換為 rgb
	cv::Mat img2RGB(cv::Mat img);
	// 圖片變?yōu)?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);
	// 預(yù)測出來的框根據(jù)原始圖片還原算法
	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());
			}
			// 加了黑邊之后預(yù)測結(jié)果可能在黑邊上,就會造成結(jié)果為負(fù)數(shù)
			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;
}

?這個(gè)效果是讀取攝像圖進(jìn)行試試檢測博文中有將攝像頭替換為圖片進(jìn)行檢測的案例

c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)

?文章來源地址http://www.zghlxwxcb.cn/news/detail-469191.html

看得懂就看,看不懂的評論區(qū)問我

到了這里,關(guān)于c++讀取yolov5模型進(jìn)行目標(biāo)檢測(讀取攝像頭實(shí)時(shí)監(jiān)測)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Opencv C++實(shí)現(xiàn)yolov5部署onnx模型完成目標(biāo)檢測

    頭文件 命名空間 結(jié)構(gòu)體 Net_config 里面存了三個(gè)閾值和模型地址,其中 置信度 ,顧名思義,看檢測出來的物體的精準(zhǔn)度。以測量值為中心,在一定范圍內(nèi),真值出現(xiàn)在該范圍內(nèi)的幾率。 endsWith()函數(shù) 判斷sub是不是s的子串 anchors_640圖像接收數(shù)組 根據(jù)圖像大小,選擇相應(yīng)長度的

    2024年02月13日
    瀏覽(25)
  • 利用yolov5進(jìn)行目標(biāo)檢測,并將檢測到的目標(biāo)裁剪出來

    利用yolov5進(jìn)行目標(biāo)檢測,并將檢測到的目標(biāo)裁剪出來

    寫在前面:關(guān)于yolov5的調(diào)試運(yùn)行在這里不做過多贅述,有關(guān)yolov5的調(diào)試運(yùn)行請看: https://www.bilibili.com/video/BV1tf4y1t7ru/spm_id_from=333.999.0.0vd_source=043dc71f3eaf6a0ccb6dada9dbd8be37 本文章主要講解的是裁剪。 需求:識別圖片中的人物并將其裁剪出來 如果只需識別人物的話,那么只需在y

    2024年02月02日
    瀏覽(18)
  • Yolov5同時(shí)進(jìn)行目標(biāo)檢測和分割分割

    Yolov5同時(shí)進(jìn)行目標(biāo)檢測和分割分割

    基于yolov5(v6.0分支)的多任務(wù)檢測和分割模型。 之前很早就萌生idea在yolov5基礎(chǔ)上添加一個(gè)分割頭用于語義分割,近期正好也有論文YLOLOP是這么做的. 這里基于yolov5最新分支修改,主要改動如下: 1 . 解耦頭:實(shí)驗(yàn)在小數(shù)據(jù)集上有一定效果(map 1%+ ),大數(shù)據(jù)集上提升不明顯; 2.

    2024年02月05日
    瀏覽(18)
  • 記錄使用yolov5進(jìn)行旋轉(zhuǎn)目標(biāo)的檢測

    記錄使用yolov5進(jìn)行旋轉(zhuǎn)目標(biāo)的檢測

    由于實(shí)習(xí)公司需要使用到旋轉(zhuǎn)目標(biāo)的檢測,所以這幾天學(xué)習(xí)了相關(guān)知識,并找了許多資料,饒了許多的彎路。下面記錄下項(xiàng)目的整個(gè)實(shí)現(xiàn)過程。 我參考的是以下幾位博主: DOTAv2遙感圖像旋轉(zhuǎn)目標(biāo)檢測競賽經(jīng)驗(yàn)分享(Swin Transformer + Anchor free/based方案) - 知乎 小雞燉技術(shù)的個(gè)人

    2024年02月02日
    瀏覽(28)
  • 【目標(biāo)檢測】yolov5模型詳解

    【目標(biāo)檢測】yolov5模型詳解

    yolov5于2020年由glenn-jocher首次提出,直至今日yolov5仍然在不斷進(jìn)行升級迭代。 Yolov5有YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x四個(gè)版本。文件中,這幾個(gè)模型的結(jié)構(gòu)基本一樣,不同的是depth_multiple模型深度和width_multiple模型寬度這兩個(gè)參數(shù)。 yolov5主要分為以下幾部分: Input:輸入 Backbone:

    2024年02月07日
    瀏覽(26)
  • 【目標(biāo)檢測】YOLOv5:模型構(gòu)建解析

    【目標(biāo)檢測】YOLOv5:模型構(gòu)建解析

    最近在看一些目標(biāo)檢測的最新論文和代碼,大多數(shù)都是在YOLOv5的基礎(chǔ)上進(jìn)行魔改。 改的最多的基本是原版本的網(wǎng)絡(luò)結(jié)構(gòu),這篇博文就從源碼角度來解析YOLOv5中,模型是如何構(gòu)建出來的。 本文使用的是YOLOv5-5.0版本。 在YOLOv5中,模型結(jié)構(gòu)基本是寫在了 .yaml 中,5.0版本的YOLOv5共

    2024年02月06日
    瀏覽(21)
  • yolov5模型(.pt)在RK3588(S)上的部署(實(shí)時(shí)攝像頭檢測)

    github倉庫 所需: 安裝了Ubuntu20系統(tǒng)的RK3588 安裝了Ubuntu18的電腦或者虛擬機(jī) 一、yolov5 PT模型獲取 Anaconda教程 YOLOv5教程 經(jīng)過上面兩個(gè)教程之后,你應(yīng)該獲取了自己的 best.pt 文件 二、PT模型轉(zhuǎn)onnx模型 將 models/yolo.py 文件中的 class 類下的 forward 函數(shù)由: 改為: 將 export.py 文件中的

    2024年02月06日
    瀏覽(24)
  • YOLOv5+BiSeNet——同時(shí)進(jìn)行目標(biāo)檢測和語義分割

    YOLOv5+BiSeNet——同時(shí)進(jìn)行目標(biāo)檢測和語義分割

    在Gayhub上看到個(gè)項(xiàng)目,有人在YOLOv5的基礎(chǔ)上,新增了一個(gè)分割頭,把BiSeNet語義分割算法加入到了目標(biāo)檢測中,使其能夠同時(shí)進(jìn)行目標(biāo)檢測和語義分割。 項(xiàng)目地址:https://github.com/TomMao23/multiyolov5 先看我使用原作者提供的模型,復(fù)刻出來的效果: (本來想放視頻的,不過傳了兩

    2024年02月07日
    瀏覽(20)
  • yolov5目標(biāo)檢測多線程C++部署

    yolov5目標(biāo)檢測多線程C++部署

    下面的代碼搭建了簡單的一個(gè)生產(chǎn)者-消費(fèi)者模型,在capture()函數(shù)中進(jìn)行入隊(duì)操作,infer()函數(shù)中進(jìn)行出隊(duì)操作,為了模擬采圖-推理流程,在函數(shù)中調(diào)用Sleep()函數(shù)延時(shí)。 輸出結(jié)果: 現(xiàn)在我們把capture函數(shù)中的Sleep(1000)改成Sleep(500)來模擬生產(chǎn)者加速生產(chǎn),再次執(zhí)行程序,則輸出:

    2024年02月13日
    瀏覽(24)
  • 【目標(biāo)檢測】YOLOv5算法實(shí)現(xiàn)(九):模型預(yù)測

    【目標(biāo)檢測】YOLOv5算法實(shí)現(xiàn)(九):模型預(yù)測

    ??本系列文章記錄本人碩士階段YOLO系列目標(biāo)檢測算法自學(xué)及其代碼實(shí)現(xiàn)的過程。其中算法具體實(shí)現(xiàn)借鑒于ultralytics YOLO源碼Github,刪減了源碼中部分內(nèi)容,滿足個(gè)人科研需求。 ??本系列文章主要以YOLOv5為例完成算法的實(shí)現(xiàn),后續(xù)修改、增加相關(guān)模塊即可實(shí)現(xiàn)其他版本的

    2024年01月21日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包