YoloFeatureExtractor.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. 
  2. #include "YoloFeatureExtractor.h"
  3. #include <fstream>
  4. #include <algorithm>
  5. #include <iostream>
  6. #include <opencv2/core/ocl.hpp>
  7. YoloFeatureExtractor::YoloFeatureExtractor(const std::string & modelPath, const std::string & classesPath)
  8. : inputWidth(640), inputHeight(640)
  9. {
  10. net = cv::dnn::readNetFromONNX(modelPath);
  11. loadClassNames(classesPath);
  12. }
  13. void YoloFeatureExtractor::initOpenCL()
  14. {
  15. if (cv::ocl::haveOpenCL())
  16. {
  17. std::cout << "OpenCL is available. Enabling OpenCL for DNN module." << std::endl;
  18. //net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
  19. //net.setPreferableTarget(cv::dnn::DNN_TARGET_OPENCL);
  20. }
  21. else
  22. {
  23. std::cout << "OpenCL is not available. Using default backend and target." << std::endl;
  24. net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
  25. net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
  26. }
  27. }
  28. void YoloFeatureExtractor::loadClassNames(const std::string & file)
  29. {
  30. std::ifstream ifs(file);
  31. std::string line;
  32. while (std::getline(ifs, line))
  33. {
  34. classNames.push_back(line);
  35. }
  36. }
  37. std::vector<float> YoloFeatureExtractor::extractFeatures(const std::string & imagePath)
  38. {
  39. auto start_time = std::chrono::high_resolution_clock::now();
  40. cv::Mat image = cv::imread(imagePath);
  41. if (image.empty())
  42. {
  43. throw std::runtime_error("Could not load image: " + imagePath);
  44. }
  45. cv::Mat blob;
  46. cv::dnn::blobFromImage(image, blob, 1.0 / 255.0, cv::Size(inputWidth, inputHeight), cv::Scalar(0, 0, 0), true, false);
  47. net.setInput(blob);
  48. auto start_time2 = std::chrono::high_resolution_clock::now();
  49. std::vector<cv::Mat> outputs;
  50. net.forward(outputs, net.getUnconnectedOutLayersNames());
  51. auto start_time3 = std::chrono::high_resolution_clock::now();
  52. std::vector<float> features;
  53. for (size_t i = 0; i < outputs.size(); ++i)
  54. {
  55. float * data = (float *)outputs[i].data;
  56. int totalElements = outputs[i].total();
  57. for (int idx = 0; idx < totalElements; ++idx)
  58. {
  59. features.push_back(data[idx]);
  60. }
  61. }
  62. auto duration1 = std::chrono::duration_cast<std::chrono::milliseconds>(start_time2 - start_time);
  63. auto duration2 = std::chrono::duration_cast<std::chrono::milliseconds>(start_time3 - start_time2);
  64. auto totalDuration = std::chrono::duration_cast<std::chrono::milliseconds>(start_time3 - start_time);
  65. std::cout << "图片前期处理耗时: " << duration1.count() << " 毫秒" << std::endl;
  66. std::cout << "模型推理耗时: " << duration2.count() << " 毫秒" << std::endl;
  67. std::cout << "总耗时: " << totalDuration.count() << " 毫秒" << std::endl;
  68. return features;
  69. }
  70. std::vector<float> YoloFeatureExtractor::extractBackboneFeatures(const std::string & imagePath)
  71. {
  72. cv::Mat image = cv::imread(imagePath);
  73. if (image.empty())
  74. {
  75. throw std::runtime_error("Could not load image: " + imagePath);
  76. }
  77. cv::Mat blob;
  78. cv::dnn::blobFromImage(image, blob, 1.0 / 255.0, cv::Size(inputWidth, inputHeight), cv::Scalar(0, 0, 0), true, false);
  79. net.setInput(blob);
  80. std::vector<cv::String> layerNames = net.getLayerNames();
  81. std::vector<cv::String> backboneLayers;
  82. for (const auto & name : layerNames)
  83. {
  84. if (name.find("backbone") != std::string::npos ||
  85. name.find("conv") != std::string::npos ||
  86. name.find("stage") != std::string::npos)
  87. {
  88. backboneLayers.push_back(name);
  89. }
  90. }
  91. if (backboneLayers.empty())
  92. {
  93. backboneLayers.push_back(layerNames[layerNames.size() / 2]);
  94. }
  95. std::vector<cv::Mat> outputs;
  96. net.forward(outputs, backboneLayers);
  97. std::vector<float> features;
  98. for (size_t i = 0; i < outputs.size(); ++i)
  99. {
  100. cv::Mat output = outputs[i];
  101. features.reserve(features.size() + output.total());
  102. for (int j = 0; j < output.total(); ++j)
  103. {
  104. features.push_back(output.at<float>(j));
  105. }
  106. }
  107. return features;
  108. }
  109. std::vector<std::vector<float>> YoloFeatureExtractor::extractROIFeatures(const std::string & imagePath)
  110. {
  111. cv::Mat image = cv::imread(imagePath);
  112. if (image.empty())
  113. {
  114. throw std::runtime_error("Could not load image: " + imagePath);
  115. }
  116. cv::Mat blob;
  117. cv::dnn::blobFromImage(image, blob, 1.0 / 255.0, cv::Size(inputWidth, inputHeight), cv::Scalar(0, 0, 0), true, false);
  118. net.setInput(blob);
  119. std::vector<cv::Mat> outputs;
  120. net.forward(outputs, net.getUnconnectedOutLayersNames());
  121. const float CONFIDENCE_THRESHOLD = 0.5;
  122. const float NMS_THRESHOLD = 0.4;
  123. std::vector<int> classIds;
  124. std::vector<float> confidences;
  125. std::vector<cv::Rect> boxes;
  126. float x_factor = static_cast<float>(image.cols) / inputWidth;
  127. float y_factor = static_cast<float>(image.rows) / inputHeight;
  128. for (size_t outputIdx = 0; outputIdx < outputs.size(); ++outputIdx)
  129. {
  130. float * data = (float *)outputs[outputIdx].data;
  131. int rows = outputs[outputIdx].rows;
  132. int dimensions = outputs[outputIdx].cols;
  133. for (int i = 0; i < rows; ++i)
  134. {
  135. float objectness = data[4];
  136. if (objectness >= CONFIDENCE_THRESHOLD)
  137. {
  138. std::vector<float> probs;
  139. for (int c = 5; c < dimensions; ++c)
  140. {
  141. probs.push_back(data[c]);
  142. }
  143. int maxClassId = 0;
  144. float maxScore = probs[0];
  145. for (size_t p = 1; p < probs.size(); ++p)
  146. {
  147. if (probs[p] > maxScore)
  148. {
  149. maxScore = probs[p];
  150. maxClassId = static_cast<int>(p);
  151. }
  152. }
  153. if (maxScore > CONFIDENCE_THRESHOLD)
  154. {
  155. confidences.push_back(objectness * maxScore);
  156. classIds.push_back(maxClassId);
  157. float x = data[0];
  158. float y = data[1];
  159. float w = data[2];
  160. float h = data[3];
  161. int left = static_cast<int>((x - 0.5 * w) * x_factor);
  162. int top = static_cast<int>((y - 0.5 * h) * y_factor);
  163. int width = static_cast<int>(w * x_factor);
  164. int height = static_cast<int>(h * y_factor);
  165. boxes.push_back(cv::Rect(left, top, width, height));
  166. }
  167. }
  168. data += dimensions;
  169. }
  170. }
  171. std::vector<int> nms_result;
  172. cv::dnn::NMSBoxes(boxes, confidences, CONFIDENCE_THRESHOLD, NMS_THRESHOLD, nms_result);
  173. std::vector<std::vector<float>> roiFeatures;
  174. for (size_t i = 0; i < nms_result.size(); ++i)
  175. {
  176. int idx = nms_result[i];
  177. cv::Rect box = boxes[idx];
  178. box.x = std::max(0, std::min(box.x, image.cols - 1));
  179. box.y = std::max(0, std::min(box.y, image.rows - 1));
  180. box.width = std::max(0, std::min(box.width, image.cols - box.x));
  181. box.height = std::max(0, std::min(box.height, image.rows - box.y));
  182. std::vector<float> roiFeature;
  183. roiFeature.push_back(static_cast<float>(box.x) / image.cols);
  184. roiFeature.push_back(static_cast<float>(box.y) / image.rows);
  185. roiFeature.push_back(static_cast<float>(box.width) / image.cols);
  186. roiFeature.push_back(static_cast<float>(box.height) / image.rows);
  187. roiFeature.push_back(confidences[idx]);
  188. roiFeature.push_back(static_cast<float>(classIds[idx]));
  189. roiFeatures.push_back(roiFeature);
  190. }
  191. return roiFeatures;
  192. }