当前位置:   article > 正文

opencv+yolov8实现监控画面报警功能_利用opencv实时获取图像并识别文字发送报警信息

利用opencv实时获取图像并识别文字发送报警信息

项目背景

最近停在门前的车被人开走了,虽然有监控,但是看监控太麻烦了,于是想着框选一个区域用yolov8直接检测闯入到这个区域的所有目标,这样1ms一帧,很快就可以跑完一天的视频

用到的技术

  1. C++
  2. OpenCV
  3. Yolov8 + OnnxRuntime

yolov8介绍

  • YOLOv8支持Pose和Segment,在使用TensorRT可以跑到1-2ms一帧
  • YOLOv8提供了一个全新的SOTA模型,包括P5 640和P6 1280分辨率的目标检测网络和基于YOLACT的实例分割模型。
  • YOLOv8和YOLOv5一样,基于缩放系数也提供了N/S/M/L/X尺度的不同大小模型,用于满足不同场景需求。
  • YOLOv8骨干网络和Neck部分可能参考了YOLOv7 ELAN设计思想,将YOLOv5的C3结构换成了梯度流更丰富的C2f结构,并对不同尺度模型调整了不同的通道数。
  • YOLOv8 Head部分相比YOLOv5改动较大,换成了目前主流的解耦头结构,将分类和检测头分离,同时也从Anchor-Based换成了Anchor-Free。
  • YOLOv8 Loss计算方面采用了TaskAlignedAssigner正样本分配策略,并引入了Distribution Focal Loss。
  • YOLOv8训练的数据增强部分引入了YOLOX中的最后10 epoch关闭Mosiac增强的操作,可以有效地提升精度。

实现步骤

  1. 首先打开视频第一帧,框选区域,我们直接使用opencv实现这个功能
  2. 加载模型检测画面中的所有对象
  3. 计算IOU,如果有重合就保存这一帧具体信息
  4. 跟踪闯入画面的目标,否则会重复保存信息

使用opencv打开视频,并框选区域

  1. #include <opencv2/opencv.hpp>
  2. #include "inference.h"
  3. using namespace cv;
  4. // 定义一个全局变量,用于存放鼠标框选的矩形区域
  5. Rect g_rect;
  6. // 定义一个全局变量,用于标记鼠标是否按下
  7. bool g_bDrawingBox = false;
  8. // 定义一个回调函数,用于处理鼠标事件
  9. void on_MouseHandle(int event, int x, int y, int flags, void* param)
  10. {
  11. // 将param转换为Mat类型的指针
  12. Mat& image = *(Mat*) param;
  13. // 根据不同的鼠标事件进行处理
  14. switch (event)
  15. {
  16. // 鼠标左键按下事件
  17. case EVENT_LBUTTONDOWN:
  18. {
  19. // 标记鼠标已按下
  20. g_bDrawingBox = true;
  21. // 记录矩形框的起始点
  22. g_rect.x = x;
  23. g_rect.y = y;
  24. break;
  25. }
  26. // 鼠标移动事件
  27. case EVENT_MOUSEMOVE:
  28. {
  29. // 如果鼠标已按下,更新矩形框的宽度和高度
  30. if (g_bDrawingBox)
  31. {
  32. g_rect.width = x - g_rect.x;
  33. g_rect.height = y - g_rect.y;
  34. }
  35. break;
  36. }
  37. // 鼠标左键松开事件
  38. case EVENT_LBUTTONUP:
  39. {
  40. // 标记鼠标已松开
  41. g_bDrawingBox = false;
  42. // 如果矩形框的宽度和高度为正,绘制矩形框到图像上
  43. if (g_rect.width > 0 && g_rect.height > 0)
  44. {
  45. rectangle(image, g_rect, Scalar(0, 255, 0));
  46. }
  47. break;
  48. }
  49. }
  50. }
  51. int main(int argc, char* argv[])
  52. {
  53. // 读取视频文件
  54. cv::VideoCapture vc;
  55. vc.open(argv[1]);
  56. if(vc.isOpened()){
  57. cv::Mat frame;
  58. vc >> frame;
  59. if(!frame.empty()){
  60. // 创建一个副本图像,用于显示框选过程
  61. Mat temp;
  62. frame.copyTo(temp);
  63. // 创建一个窗口,显示图像
  64. namedWindow("image");
  65. // 设置鼠标回调函数,传入副本图像作为参数
  66. setMouseCallback("image", on_MouseHandle, (void*)&temp);
  67. while (1)
  68. {
  69. // 如果鼠标正在框选,绘制一个虚线矩形框到副本图像上,并显示框的大小和坐标
  70. if (g_bDrawingBox)
  71. {
  72. temp.copyTo(frame);
  73. rectangle(frame, g_rect, Scalar(0, 255, 0), 1, LINE_AA);
  74. char text[32];
  75. sprintf(text, "w=%d, h=%d", g_rect.width, g_rect.height);
  76. putText(frame, text, Point(g_rect.x + 5, g_rect.y - 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
  77. }
  78. // 显示副本图像
  79. imshow("image", frame);
  80. // 等待按键,如果按下ESC键,退出循环
  81. if (waitKey(10) == 27)
  82. {
  83. break;
  84. }
  85. }
  86. while(!frame.empty()){
  87. cv::imshow("image", frame);
  88. cv::waitKey(1);
  89. vc >> frame;
  90. }
  91. }
  92. }
  93. return 0;
  94. }

使用YoloV8检测目标

inference.h

  1. #pragma once
  2. #define RET_OK nullptr
  3. #ifdef _WIN32
  4. #include <Windows.h>
  5. #include <direct.h>
  6. #include <io.h>
  7. #endif
  8. #include <string>
  9. #include <vector>
  10. #include <cstdio>
  11. #include <opencv2/opencv.hpp>
  12. #include "onnxruntime_cxx_api.h"
  13. #ifdef USE_CUDA
  14. #include <cuda_fp16.h>
  15. #endif
  16. enum MODEL_TYPE {
  17. //FLOAT32 MODEL
  18. YOLO_ORIGIN_V5 = 0,
  19. YOLO_ORIGIN_V8 = 1,//only support v8 detector currently
  20. YOLO_POSE_V8 = 2,
  21. YOLO_CLS_V8 = 3,
  22. YOLO_ORIGIN_V8_HALF = 4,
  23. YOLO_POSE_V8_HALF = 5,
  24. YOLO_CLS_V8_HALF = 6
  25. };
  26. typedef struct _DCSP_INIT_PARAM {
  27. std::string ModelPath;
  28. MODEL_TYPE ModelType = YOLO_ORIGIN_V8;
  29. std::vector<int> imgSize = {640, 640};
  30. float RectConfidenceThreshold = 0.6;
  31. float iouThreshold = 0.5;
  32. bool CudaEnable = false;
  33. int LogSeverityLevel = 3;
  34. int IntraOpNumThreads = 1;
  35. } DCSP_INIT_PARAM;
  36. typedef struct _DCSP_RESULT {
  37. int classId;
  38. float confidence;
  39. cv::Rect box;
  40. } DCSP_RESULT;
  41. class DCSP_CORE {
  42. public:
  43. DCSP_CORE();
  44. ~DCSP_CORE();
  45. public:
  46. char *CreateSession(DCSP_INIT_PARAM &iParams);
  47. char *RunSession(cv::Mat &iImg, std::vector<DCSP_RESULT> &oResult);
  48. char *WarmUpSession();
  49. template<typename N>
  50. char *TensorProcess(clock_t &starttime_1, cv::Mat &iImg, N &blob, std::vector<int64_t> &inputNodeDims,
  51. std::vector<DCSP_RESULT> &oResult);
  52. std::vector<std::string> classes{};
  53. private:
  54. Ort::Env env;
  55. Ort::Session *session;
  56. bool cudaEnable;
  57. Ort::RunOptions options;
  58. std::vector<const char *> inputNodeNames;
  59. std::vector<const char *> outputNodeNames;
  60. MODEL_TYPE modelType;
  61. std::vector<int> imgSize;
  62. float rectConfidenceThreshold;
  63. float iouThreshold;
  64. };

inference.cpp

  1. #include "inference.h"
  2. #include <regex>
  3. #define benchmark
  4. DCSP_CORE::DCSP_CORE() {
  5. }
  6. DCSP_CORE::~DCSP_CORE() {
  7. delete session;
  8. }
  9. #ifdef USE_CUDA
  10. namespace Ort
  11. {
  12. template<>
  13. struct TypeToTensorType<half> { static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; };
  14. }
  15. #endif
  16. template<typename T>
  17. char *BlobFromImage(cv::Mat &iImg, T &iBlob) {
  18. int channels = iImg.channels();
  19. int imgHeight = iImg.rows;
  20. int imgWidth = iImg.cols;
  21. for (int c = 0; c < channels; c++) {
  22. for (int h = 0; h < imgHeight; h++) {
  23. for (int w = 0; w < imgWidth; w++) {
  24. iBlob[c * imgWidth * imgHeight + h * imgWidth + w] = typename std::remove_pointer<T>::type(
  25. (iImg.at<cv::Vec3b>(h, w)[c]) / 255.0f);
  26. }
  27. }
  28. }
  29. return RET_OK;
  30. }
  31. char *PostProcess(cv::Mat &iImg, std::vector<int> iImgSize, cv::Mat &oImg) {
  32. cv::Mat img = iImg.clone();
  33. cv::resize(iImg, oImg, cv::Size(iImgSize.at(0), iImgSize.at(1)));
  34. if (img.channels() == 1) {
  35. cv::cvtColor(oImg, oImg, cv::COLOR_GRAY2BGR);
  36. }
  37. cv::cvtColor(oImg, oImg, cv::COLOR_BGR2RGB);
  38. return RET_OK;
  39. }
  40. char *DCSP_CORE::CreateSession(DCSP_INIT_PARAM &iParams) {
  41. char *Ret = RET_OK;
  42. std::regex pattern("[\u4e00-\u9fa5]");
  43. bool result = std::regex_search(iParams.ModelPath, pattern);
  44. if (result) {
  45. Ret = "[DCSP_ONNX]:Model path error.Change your model path without chinese characters.";
  46. std::cout << Ret << std::endl;
  47. return Ret;
  48. }
  49. try {
  50. rectConfidenceThreshold = iParams.RectConfidenceThreshold;
  51. iouThreshold = iParams.iouThreshold;
  52. imgSize = iParams.imgSize;
  53. modelType = iParams.ModelType;
  54. env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "Yolo");
  55. Ort::SessionOptions sessionOption;
  56. if (iParams.CudaEnable) {
  57. cudaEnable = iParams.CudaEnable;
  58. OrtCUDAProviderOptions cudaOption;
  59. cudaOption.device_id = 0;
  60. sessionOption.AppendExecutionProvider_CUDA(cudaOption);
  61. }
  62. sessionOption.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
  63. sessionOption.SetIntraOpNumThreads(iParams.IntraOpNumThreads);
  64. sessionOption.SetLogSeverityLevel(iParams.LogSeverityLevel);
  65. #ifdef _WIN32
  66. int ModelPathSize = MultiByteToWideChar(CP_UTF8, 0, iParams.ModelPath.c_str(), static_cast<int>(iParams.ModelPath.length()), nullptr, 0);
  67. wchar_t* wide_cstr = new wchar_t[ModelPathSize + 1];
  68. MultiByteToWideChar(CP_UTF8, 0, iParams.ModelPath.c_str(), static_cast<int>(iParams.ModelPath.length()), wide_cstr, ModelPathSize);
  69. wide_cstr[ModelPathSize] = L'\0';
  70. const wchar_t* modelPath = wide_cstr;
  71. #else
  72. const char *modelPath = iParams.ModelPath.c_str();
  73. #endif // _WIN32
  74. session = new Ort::Session(env, modelPath, sessionOption);
  75. Ort::AllocatorWithDefaultOptions allocator;
  76. size_t inputNodesNum = session->GetInputCount();
  77. for (size_t i = 0; i < inputNodesNum; i++) {
  78. Ort::AllocatedStringPtr input_node_name = session->GetInputNameAllocated(i, allocator);
  79. char *temp_buf = new char[50];
  80. strcpy(temp_buf, input_node_name.get());
  81. inputNodeNames.push_back(temp_buf);
  82. }
  83. size_t OutputNodesNum = session->GetOutputCount();
  84. for (size_t i = 0; i < OutputNodesNum; i++) {
  85. Ort::AllocatedStringPtr output_node_name = session->GetOutputNameAllocated(i, allocator);
  86. char *temp_buf = new char[10];
  87. strcpy(temp_buf, output_node_name.get());
  88. outputNodeNames.push_back(temp_buf);
  89. }
  90. options = Ort::RunOptions{nullptr};
  91. WarmUpSession();
  92. return RET_OK;
  93. }
  94. catch (const std::exception &e) {
  95. const char *str1 = "[DCSP_ONNX]:";
  96. const char *str2 = e.what();
  97. std::string result = std::string(str1) + std::string(str2);
  98. char *merged = new char[result.length() + 1];
  99. std::strcpy(merged, result.c_str());
  100. std::cout << merged << std::endl;
  101. delete[] merged;
  102. return "[DCSP_ONNX]:Create session failed.";
  103. }
  104. }
  105. char *DCSP_CORE::RunSession(cv::Mat &iImg, std::vector<DCSP_RESULT> &oResult) {
  106. #ifdef benchmark
  107. clock_t starttime_1 = clock();
  108. #endif // benchmark
  109. char *Ret = RET_OK;
  110. cv::Mat processedImg;
  111. PostProcess(iImg, imgSize, processedImg);
  112. if (modelType < 4) {
  113. float *blob = new float[processedImg.total() * 3];
  114. BlobFromImage(processedImg, blob);
  115. std::vector<int64_t> inputNodeDims = {1, 3, imgSize.at(0), imgSize.at(1)};
  116. TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult);
  117. } else {
  118. #ifdef USE_CUDA
  119. half* blob = new half[processedImg.total() * 3];
  120. BlobFromImage(processedImg, blob);
  121. std::vector<int64_t> inputNodeDims = { 1,3,imgSize.at(0),imgSize.at(1) };
  122. TensorProcess(starttime_1, iImg, blob, inputNodeDims, oResult);
  123. #endif
  124. }
  125. return Ret;
  126. }
  127. template<typename N>
  128. char *DCSP_CORE::TensorProcess(clock_t &starttime_1, cv::Mat &iImg, N &blob, std::vector<int64_t> &inputNodeDims,
  129. std::vector<DCSP_RESULT> &oResult) {
  130. Ort::Value inputTensor = Ort::Value::CreateTensor<typename std::remove_pointer<N>::type>(
  131. Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1),
  132. inputNodeDims.data(), inputNodeDims.size());
  133. #ifdef benchmark
  134. clock_t starttime_2 = clock();
  135. #endif // benchmark
  136. auto outputTensor = session->Run(options, inputNodeNames.data(), &inputTensor, 1, outputNodeNames.data(),
  137. outputNodeNames.size());
  138. #ifdef benchmark
  139. clock_t starttime_3 = clock();
  140. #endif // benchmark
  141. Ort::TypeInfo typeInfo = outputTensor.front().GetTypeInfo();
  142. auto tensor_info = typeInfo.GetTensorTypeAndShapeInfo();
  143. std::vector<int64_t> outputNodeDims = tensor_info.GetShape();
  144. auto output = outputTensor.front().GetTensorMutableData<typename std::remove_pointer<N>::type>();
  145. delete blob;
  146. switch (modelType) {
  147. case 1://V8_ORIGIN_FP32
  148. case 4://V8_ORIGIN_FP16
  149. {
  150. int strideNum = outputNodeDims[2];
  151. int signalResultNum = outputNodeDims[1];
  152. std::vector<int> class_ids;
  153. std::vector<float> confidences;
  154. std::vector<cv::Rect> boxes;
  155. cv::Mat rawData;
  156. if (modelType == 1) {
  157. // FP32
  158. rawData = cv::Mat(signalResultNum, strideNum, CV_32F, output);
  159. } else {
  160. // FP16
  161. rawData = cv::Mat(signalResultNum, strideNum, CV_16F, output);
  162. rawData.convertTo(rawData, CV_32F);
  163. }
  164. rawData = rawData.t();
  165. float *data = (float *) rawData.data;
  166. float x_factor = iImg.cols / 640.;
  167. float y_factor = iImg.rows / 640.;
  168. for (int i = 0; i < strideNum; ++i) {
  169. float *classesScores = data + 4;
  170. cv::Mat scores(1, this->classes.size(), CV_32FC1, classesScores);
  171. cv::Point class_id;
  172. double maxClassScore;
  173. cv::minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);
  174. if (maxClassScore > rectConfidenceThreshold) {
  175. confidences.push_back(maxClassScore);
  176. class_ids.push_back(class_id.x);
  177. float x = data[0];
  178. float y = data[1];
  179. float w = data[2];
  180. float h = data[3];
  181. int left = int((x - 0.5 * w) * x_factor);
  182. int top = int((y - 0.5 * h) * y_factor);
  183. int width = int(w * x_factor);
  184. int height = int(h * y_factor);
  185. boxes.emplace_back(left, top, width, height);
  186. }
  187. data += signalResultNum;
  188. }
  189. std::vector<int> nmsResult;
  190. cv::dnn::NMSBoxes(boxes, confidences, rectConfidenceThreshold, iouThreshold, nmsResult);
  191. for (int i = 0; i < nmsResult.size(); ++i) {
  192. int idx = nmsResult[i];
  193. DCSP_RESULT result;
  194. result.classId = class_ids[idx];
  195. result.confidence = confidences[idx];
  196. result.box = boxes[idx];
  197. oResult.push_back(result);
  198. }
  199. #ifdef benchmark
  200. clock_t starttime_4 = clock();
  201. double pre_process_time = (double) (starttime_2 - starttime_1) / CLOCKS_PER_SEC * 1000;
  202. double process_time = (double) (starttime_3 - starttime_2) / CLOCKS_PER_SEC * 1000;
  203. double post_process_time = (double) (starttime_4 - starttime_3) / CLOCKS_PER_SEC * 1000;
  204. if (cudaEnable) {
  205. std::cout << "[DCSP_ONNX(CUDA)]: " << pre_process_time << "ms pre-process, " << process_time
  206. << "ms inference, " << post_process_time << "ms post-process." << std::endl;
  207. } else {
  208. std::cout << "[DCSP_ONNX(CPU)]: " << pre_process_time << "ms pre-process, " << process_time
  209. << "ms inference, " << post_process_time << "ms post-process." << std::endl;
  210. }
  211. #endif // benchmark
  212. break;
  213. }
  214. }
  215. return RET_OK;
  216. }
  217. char *DCSP_CORE::WarmUpSession() {
  218. clock_t starttime_1 = clock();
  219. cv::Mat iImg = cv::Mat(cv::Size(imgSize.at(0), imgSize.at(1)), CV_8UC3);
  220. cv::Mat processedImg;
  221. PostProcess(iImg, imgSize, processedImg);
  222. if (modelType < 4) {
  223. float *blob = new float[iImg.total() * 3];
  224. BlobFromImage(processedImg, blob);
  225. std::vector<int64_t> YOLO_input_node_dims = {1, 3, imgSize.at(0), imgSize.at(1)};
  226. Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
  227. Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1),
  228. YOLO_input_node_dims.data(), YOLO_input_node_dims.size());
  229. auto output_tensors = session->Run(options, inputNodeNames.data(), &input_tensor, 1, outputNodeNames.data(),
  230. outputNodeNames.size());
  231. delete[] blob;
  232. clock_t starttime_4 = clock();
  233. double post_process_time = (double) (starttime_4 - starttime_1) / CLOCKS_PER_SEC * 1000;
  234. if (cudaEnable) {
  235. std::cout << "[DCSP_ONNX(CUDA)]: " << "Cuda warm-up cost " << post_process_time << " ms. " << std::endl;
  236. }
  237. } else {
  238. #ifdef USE_CUDA
  239. half* blob = new half[iImg.total() * 3];
  240. BlobFromImage(processedImg, blob);
  241. std::vector<int64_t> YOLO_input_node_dims = { 1,3,imgSize.at(0),imgSize.at(1) };
  242. Ort::Value input_tensor = Ort::Value::CreateTensor<half>(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU), blob, 3 * imgSize.at(0) * imgSize.at(1), YOLO_input_node_dims.data(), YOLO_input_node_dims.size());
  243. auto output_tensors = session->Run(options, inputNodeNames.data(), &input_tensor, 1, outputNodeNames.data(), outputNodeNames.size());
  244. delete[] blob;
  245. clock_t starttime_4 = clock();
  246. double post_process_time = (double)(starttime_4 - starttime_1) / CLOCKS_PER_SEC * 1000;
  247. if (cudaEnable)
  248. {
  249. std::cout << "[DCSP_ONNX(CUDA)]: " << "Cuda warm-up cost " << post_process_time << " ms. " << std::endl;
  250. }
  251. #endif
  252. }
  253. return RET_OK;
  254. }

main.cpp

  1. int read_coco_yaml(DCSP_CORE *&p) {
  2. // Open the YAML file
  3. std::ifstream file("coco.yaml");
  4. if (!file.is_open()) {
  5. std::cerr << "Failed to open file" << std::endl;
  6. return 1;
  7. }
  8. // Read the file line by line
  9. std::string line;
  10. std::vector<std::string> lines;
  11. while (std::getline(file, line)) {
  12. lines.push_back(line);
  13. }
  14. // Find the start and end of the names section
  15. std::size_t start = 0;
  16. std::size_t end = 0;
  17. for (std::size_t i = 0; i < lines.size(); i++) {
  18. if (lines[i].find("names:") != std::string::npos) {
  19. start = i + 1;
  20. } else if (start > 0 && lines[i].find(':') == std::string::npos) {
  21. end = i;
  22. break;
  23. }
  24. }
  25. // Extract the names
  26. std::vector<std::string> names;
  27. for (std::size_t i = start; i < end; i++) {
  28. std::stringstream ss(lines[i]);
  29. std::string name;
  30. std::getline(ss, name, ':'); // Extract the number before the delimiter
  31. std::getline(ss, name); // Extract the string after the delimiter
  32. names.push_back(name);
  33. }
  34. p->classes = names;
  35. return 0;
  36. }
  37. int main(int argc, char* argv[])
  38. {
  39. DCSP_CORE *yoloDetector = new DCSP_CORE;
  40. //std::string model_path = "yolov8n.onnx";
  41. std::string model_path = argv[1];
  42. read_coco_yaml(yoloDetector);
  43. #ifdef USE_CUDA
  44. // GPU FP32 inference
  45. DCSP_INIT_PARAM params{ model_path, YOLO_ORIGIN_V8, {640, 640}, 0.1, 0.5, true };
  46. // GPU FP16 inference
  47. // DCSP_INIT_PARAM params{ model_path, YOLO_ORIGIN_V8_HALF, {640, 640}, 0.1, 0.5, true };
  48. #else
  49. // CPU inference
  50. DCSP_INIT_PARAM params{model_path, YOLO_ORIGIN_V8, {640, 640}, 0.1, 0.5, false};
  51. #endif
  52. yoloDetector->CreateSession(params);
  53. cv::VideoCapture vc;
  54. vc.open(argv[2]);
  55. if(vc.isOpened()){
  56. cv::Mat frame;
  57. vc >> frame;
  58. while(!frame.empty()){
  59. std::vector<DCSP_RESULT> res;
  60. yoloDetector->RunSession(frame, res);
  61. for (int i = 0; i < res.size(); ++i)
  62. {
  63. DCSP_RESULT detection = res[i];
  64. cv::Rect box = detection.box;
  65. cv::RNG rng(cv::getTickCount());
  66. cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));;
  67. // Detection box
  68. cv::rectangle(frame, box, color, 2);
  69. // Detection box text
  70. std::string classString = yoloDetector->classes[detection.classId] + ' ' + std::to_string(detection.confidence).substr(0, 4);
  71. cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
  72. cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);
  73. cv::rectangle(frame, textBox, color, cv::FILLED);
  74. cv::putText(frame, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
  75. }
  76. cv::rectangle(frame, g_rect, Scalar(0, 255, 0), 3, cv::LINE_AA);
  77. cv::imshow("image", frame);
  78. cv::waitKey(1);
  79. vc >> frame;
  80. }
  81. }
  82. }

opencv的框选区域和yolov8检测目标框融合

  1. #include <opencv2/opencv.hpp>
  2. #include <fstream>
  3. #include "inference.h"
  4. using namespace cv;
  5. // 定义一个全局变量,用于存放鼠标框选的矩形区域
  6. Rect g_rect;
  7. // 定义一个全局变量,用于标记鼠标是否按下
  8. bool g_bDrawingBox = false;
  9. // 定义一个回调函数,用于处理鼠标事件
  10. void on_MouseHandle(int event, int x, int y, int flags, void* param)
  11. {
  12. // 将param转换为Mat类型的指针
  13. Mat& image = *(Mat*) param;
  14. // 根据不同的鼠标事件进行处理
  15. switch (event)
  16. {
  17. // 鼠标左键按下事件
  18. case EVENT_LBUTTONDOWN:
  19. {
  20. // 标记鼠标已按下
  21. g_bDrawingBox = true;
  22. // 记录矩形框的起始点
  23. g_rect.x = x;
  24. g_rect.y = y;
  25. break;
  26. }
  27. // 鼠标移动事件
  28. case EVENT_MOUSEMOVE:
  29. {
  30. // 如果鼠标已按下,更新矩形框的宽度和高度
  31. if (g_bDrawingBox)
  32. {
  33. g_rect.width = x - g_rect.x;
  34. g_rect.height = y - g_rect.y;
  35. }
  36. break;
  37. }
  38. // 鼠标左键松开事件
  39. case EVENT_LBUTTONUP:
  40. {
  41. // 标记鼠标已松开
  42. g_bDrawingBox = false;
  43. // 如果矩形框的宽度和高度为正,绘制矩形框到图像上
  44. if (g_rect.width > 0 && g_rect.height > 0)
  45. {
  46. rectangle(image, g_rect, Scalar(0, 255, 0));
  47. }
  48. break;
  49. }
  50. }
  51. }
  52. int read_coco_yaml(DCSP_CORE *&p) {
  53. // Open the YAML file
  54. std::ifstream file("coco.yaml");
  55. if (!file.is_open()) {
  56. std::cerr << "Failed to open file" << std::endl;
  57. return 1;
  58. }
  59. // Read the file line by line
  60. std::string line;
  61. std::vector<std::string> lines;
  62. while (std::getline(file, line)) {
  63. lines.push_back(line);
  64. }
  65. // Find the start and end of the names section
  66. std::size_t start = 0;
  67. std::size_t end = 0;
  68. for (std::size_t i = 0; i < lines.size(); i++) {
  69. if (lines[i].find("names:") != std::string::npos) {
  70. start = i + 1;
  71. } else if (start > 0 && lines[i].find(':') == std::string::npos) {
  72. end = i;
  73. break;
  74. }
  75. }
  76. // Extract the names
  77. std::vector<std::string> names;
  78. for (std::size_t i = start; i < end; i++) {
  79. std::stringstream ss(lines[i]);
  80. std::string name;
  81. std::getline(ss, name, ':'); // Extract the number before the delimiter
  82. std::getline(ss, name); // Extract the string after the delimiter
  83. names.push_back(name);
  84. }
  85. p->classes = names;
  86. return 0;
  87. }
  88. int main(int argc, char* argv[])
  89. {
  90. // 读取原始图像
  91. // Mat src = imread(argv[1]);
  92. DCSP_CORE *yoloDetector = new DCSP_CORE;
  93. //std::string model_path = "yolov8n.onnx";
  94. std::string model_path = argv[1];
  95. read_coco_yaml(yoloDetector);
  96. #ifdef USE_CUDA
  97. // GPU FP32 inference
  98. DCSP_INIT_PARAM params{ model_path, YOLO_ORIGIN_V8, {640, 640}, 0.1, 0.5, true };
  99. // GPU FP16 inference
  100. // DCSP_INIT_PARAM params{ model_path, YOLO_ORIGIN_V8_HALF, {640, 640}, 0.1, 0.5, true };
  101. #else
  102. // CPU inference
  103. DCSP_INIT_PARAM params{model_path, YOLO_ORIGIN_V8, {640, 640}, 0.1, 0.5, false};
  104. #endif
  105. yoloDetector->CreateSession(params);
  106. cv::VideoCapture vc;
  107. vc.open(argv[2]);
  108. if(vc.isOpened()){
  109. cv::Mat frame;
  110. vc >> frame;
  111. if(!frame.empty()){
  112. // 创建一个副本图像,用于显示框选过程
  113. Mat temp;
  114. frame.copyTo(temp);
  115. // 创建一个窗口,显示图像
  116. namedWindow("image");
  117. // 设置鼠标回调函数,传入副本图像作为参数
  118. setMouseCallback("image", on_MouseHandle, (void*)&temp);
  119. while (1)
  120. {
  121. // 如果鼠标正在框选,绘制一个虚线矩形框到副本图像上,并显示框的大小和坐标
  122. if (g_bDrawingBox)
  123. {
  124. temp.copyTo(frame);
  125. rectangle(frame, g_rect, Scalar(0, 255, 0), 1, LINE_AA);
  126. char text[32];
  127. sprintf(text, "w=%d, h=%d", g_rect.width, g_rect.height);
  128. putText(frame, text, Point(g_rect.x + 5, g_rect.y - 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
  129. }
  130. // 显示副本图像
  131. imshow("image", frame);
  132. // 等待按键,如果按下ESC键,退出循环
  133. if (waitKey(10) == 27)
  134. {
  135. break;
  136. }
  137. }
  138. while(!frame.empty()){
  139. std::vector<DCSP_RESULT> res;
  140. yoloDetector->RunSession(frame, res);
  141. for (int i = 0; i < res.size(); ++i)
  142. {
  143. DCSP_RESULT detection = res[i];
  144. cv::Rect box = detection.box;
  145. cv::RNG rng(cv::getTickCount());
  146. cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));;
  147. // Detection box
  148. cv::rectangle(frame, box, color, 2);
  149. // Detection box text
  150. std::string classString = yoloDetector->classes[detection.classId] + ' ' + std::to_string(detection.confidence).substr(0, 4);
  151. cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
  152. cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);
  153. cv::rectangle(frame, textBox, color, cv::FILLED);
  154. cv::putText(frame, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
  155. }
  156. cv::rectangle(frame, g_rect, Scalar(0, 255, 0), 3, cv::LINE_AA);
  157. cv::imshow("image", frame);
  158. cv::waitKey(1);
  159. vc >> frame;
  160. }
  161. }
  162. }
  163. return 0;
  164. }

计算预警区域和目标框重合度

  1. double calIou(const cv::Rect& rc1, const cv::Rect& rc2)
  2. {
  3. cv::Rect intersection = rc1 & rc2;
  4. if (!intersection.empty()) {
  5. double intersectionArea = intersection.width * intersection.height;
  6. double rect1Area = rc1.width * rc1.height;
  7. double rect2Area = rc2.width * rc2.height;
  8. // 计算IOU
  9. double iou = intersectionArea / (rect1Area + rect2Area - intersectionArea);
  10. return iou;
  11. } else {
  12. // 没有重叠,IOU为0
  13. return 0.0;
  14. }
  15. }

跟踪实现

不断的去循环激活的目标,来过滤掉重复的代码,这块以后实现

完整代码

  1. #include <opencv2/opencv.hpp>
  2. #include <fstream>
  3. #include "inference.h"
  4. using namespace cv;
  5. // 定义一个全局变量,用于存放鼠标框选的矩形区域
  6. Rect g_rect;
  7. // 定义一个全局变量,用于标记鼠标是否按下
  8. bool g_bDrawingBox = false;
  9. // 定义一个回调函数,用于处理鼠标事件
  10. void on_MouseHandle(int event, int x, int y, int flags, void* param)
  11. {
  12. // 将param转换为Mat类型的指针
  13. Mat& image = *(Mat*) param;
  14. // 根据不同的鼠标事件进行处理
  15. switch (event)
  16. {
  17. // 鼠标左键按下事件
  18. case EVENT_LBUTTONDOWN:
  19. {
  20. // 标记鼠标已按下
  21. g_bDrawingBox = true;
  22. // 记录矩形框的起始点
  23. g_rect.x = x;
  24. g_rect.y = y;
  25. break;
  26. }
  27. // 鼠标移动事件
  28. case EVENT_MOUSEMOVE:
  29. {
  30. // 如果鼠标已按下,更新矩形框的宽度和高度
  31. if (g_bDrawingBox)
  32. {
  33. g_rect.width = x - g_rect.x;
  34. g_rect.height = y - g_rect.y;
  35. }
  36. break;
  37. }
  38. // 鼠标左键松开事件
  39. case EVENT_LBUTTONUP:
  40. {
  41. // 标记鼠标已松开
  42. g_bDrawingBox = false;
  43. // 如果矩形框的宽度和高度为正,绘制矩形框到图像上
  44. if (g_rect.width > 0 && g_rect.height > 0)
  45. {
  46. rectangle(image, g_rect, Scalar(0, 255, 0));
  47. }
  48. break;
  49. }
  50. }
  51. }
  52. int read_coco_yaml(DCSP_CORE *&p) {
  53. // Open the YAML file
  54. std::ifstream file("coco.yaml");
  55. if (!file.is_open()) {
  56. std::cerr << "Failed to open file" << std::endl;
  57. return 1;
  58. }
  59. // Read the file line by line
  60. std::string line;
  61. std::vector<std::string> lines;
  62. while (std::getline(file, line)) {
  63. lines.push_back(line);
  64. }
  65. // Find the start and end of the names section
  66. std::size_t start = 0;
  67. std::size_t end = 0;
  68. for (std::size_t i = 0; i < lines.size(); i++) {
  69. if (lines[i].find("names:") != std::string::npos) {
  70. start = i + 1;
  71. } else if (start > 0 && lines[i].find(':') == std::string::npos) {
  72. end = i;
  73. break;
  74. }
  75. }
  76. // Extract the names
  77. std::vector<std::string> names;
  78. for (std::size_t i = start; i < end; i++) {
  79. std::stringstream ss(lines[i]);
  80. std::string name;
  81. std::getline(ss, name, ':'); // Extract the number before the delimiter
  82. std::getline(ss, name); // Extract the string after the delimiter
  83. names.push_back(name);
  84. }
  85. p->classes = names;
  86. return 0;
  87. }
  88. double calIou(const cv::Rect& rc1, const cv::Rect& rc2)
  89. {
  90. cv::Rect intersection = rc1 & rc2;
  91. if (!intersection.empty()) {
  92. double intersectionArea = intersection.width * intersection.height;
  93. double rect1Area = rc1.width * rc1.height;
  94. double rect2Area = rc2.width * rc2.height;
  95. // 计算IOU
  96. double iou = intersectionArea / (rect1Area + rect2Area - intersectionArea);
  97. return iou;
  98. } else {
  99. // 没有重叠,IOU为0
  100. return 0.0;
  101. }
  102. }
  103. int main(int argc, char* argv[])
  104. {
  105. // 读取原始图像
  106. // Mat src = imread(argv[1]);
  107. DCSP_CORE *yoloDetector = new DCSP_CORE;
  108. //std::string model_path = "yolov8n.onnx";
  109. std::string model_path = argv[1];
  110. read_coco_yaml(yoloDetector);
  111. #ifdef USE_CUDA
  112. // GPU FP32 inference
  113. DCSP_INIT_PARAM params{ model_path, YOLO_ORIGIN_V8, {640, 640}, 0.1, 0.5, true };
  114. // GPU FP16 inference
  115. // DCSP_INIT_PARAM params{ model_path, YOLO_ORIGIN_V8_HALF, {640, 640}, 0.1, 0.5, true };
  116. #else
  117. // CPU inference
  118. DCSP_INIT_PARAM params{model_path, YOLO_ORIGIN_V8, {640, 640}, 0.1, 0.5, false};
  119. #endif
  120. yoloDetector->CreateSession(params);
  121. cv::VideoCapture vc;
  122. vc.open(argv[2]);
  123. if(vc.isOpened()){
  124. cv::Mat frame;
  125. vc >> frame;
  126. if(!frame.empty()){
  127. // 创建一个副本图像,用于显示框选过程
  128. Mat temp;
  129. frame.copyTo(temp);
  130. // 创建一个窗口,显示图像
  131. namedWindow("image");
  132. // 设置鼠标回调函数,传入副本图像作为参数
  133. setMouseCallback("image", on_MouseHandle, (void*)&temp);
  134. while (1)
  135. {
  136. // 如果鼠标正在框选,绘制一个虚线矩形框到副本图像上,并显示框的大小和坐标
  137. if (g_bDrawingBox)
  138. {
  139. temp.copyTo(frame);
  140. rectangle(frame, g_rect, Scalar(0, 255, 0), 1, LINE_AA);
  141. char text[32];
  142. sprintf(text, "w=%d, h=%d", g_rect.width, g_rect.height);
  143. putText(frame, text, Point(g_rect.x + 5, g_rect.y - 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));
  144. }
  145. // 显示副本图像
  146. imshow("image", frame);
  147. // 等待按键,如果按下ESC键,退出循环
  148. if (waitKey(10) == 27)
  149. {
  150. break;
  151. }
  152. }
  153. while(!frame.empty()){
  154. std::vector<DCSP_RESULT> res;
  155. yoloDetector->RunSession(frame, res);
  156. for (int i = 0; i < res.size(); ++i)
  157. {
  158. DCSP_RESULT detection = res[i];
  159. cv::Rect box = detection.box;
  160. cv::RNG rng(cv::getTickCount());
  161. cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));;
  162. // Detection box
  163. cv::rectangle(frame, box, color, 2);
  164. // Detection box text
  165. std::string classString = yoloDetector->classes[detection.classId] + ' ' + std::to_string(detection.confidence).substr(0, 4);
  166. cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
  167. cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);
  168. cv::rectangle(frame, textBox, color, cv::FILLED);
  169. cv::putText(frame, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
  170. double iou = calIou(g_rect, box);
  171. if(iou > 0)
  172. std::cout << "iou:" << iou << std::endl;
  173. }
  174. cv::rectangle(frame, g_rect, Scalar(0, 255, 0), 3, cv::LINE_AA);
  175. cv::imshow("image", frame);
  176. cv::waitKey(1);
  177. vc >> frame;
  178. }
  179. }
  180. }
  181. return 0;
  182. }

参考

yolov8

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/77952
推荐阅读
相关标签
  

闽ICP备14008679号