|
|
@@ -124,6 +124,8 @@ std::vector<float> YoloFeatureManager::extractFeatures(const std::string & image
|
|
|
|
|
|
std::vector<float> YoloFeatureManager::extractFeatures(cv::Mat& image)
|
|
|
{
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
+
|
|
|
try
|
|
|
{
|
|
|
auto time_1 = std::chrono::high_resolution_clock::now();
|
|
|
@@ -141,7 +143,7 @@ std::vector<float> YoloFeatureManager::extractFeatures(cv::Mat& image)
|
|
|
auto time_2 = std::chrono::high_resolution_clock::now();
|
|
|
|
|
|
//获取模型的所有层名称(调试用)
|
|
|
- //std::vector<cv::String> layerNames = net.getLayerNames();
|
|
|
+ std::vector<cv::String> layerNames = net.getLayerNames();
|
|
|
|
|
|
// 获取Flatten层输出(yolo26s-cls的Flatten层名称为 "onnx_node!/model.10/Flatten",这是GAP后分类头前的一层)'
|
|
|
// GAP层是onnx_node!/model.10/pool/GlobalAveragePool
|
|
|
@@ -195,138 +197,10 @@ std::vector<float> YoloFeatureManager::extractFeatures(cv::Mat& image)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void YoloFeatureManager::Detection(const std::string & imagePath)
|
|
|
-{
|
|
|
- cv::Mat image = cv::imread(imagePath);
|
|
|
- if (image.empty())
|
|
|
- {
|
|
|
- throw std::runtime_error("Could not load image: " + imagePath);
|
|
|
- }
|
|
|
-
|
|
|
- // 构造输入blob(图像预处理)
|
|
|
- // 参数说明:输入图像、缩放因子、输入尺寸、均值归一化、是否交换RB通道、是否裁剪
|
|
|
- cv::Mat blob;
|
|
|
- cv::dnn::blobFromImage(image, blob, 1.0 / 255, cv::Size(inputWidth, inputHeight), cv::Scalar(0, 0, 0), true, false);
|
|
|
-
|
|
|
- // -------------------------- 4. 模型推理 --------------------------
|
|
|
- // 设置网络输入
|
|
|
- net.setInput(blob);
|
|
|
-
|
|
|
- // 获取输出层名称
|
|
|
- std::vector<std::string> outLayerNames = net.getUnconnectedOutLayersNames();
|
|
|
-
|
|
|
- // 前向推理
|
|
|
- std::vector<cv::Mat> outs;
|
|
|
- net.forward(outs, outLayerNames);
|
|
|
-
|
|
|
- // -------------------------- 5. 解析推理结果 --------------------------
|
|
|
- std::vector<cv::Rect> boxes; // 检测框
|
|
|
- std::vector<int> classIds; // 类别ID
|
|
|
- std::vector<float> confidences; // 置信度
|
|
|
-
|
|
|
- // 遍历所有输出层的结果
|
|
|
- for (const cv::Mat & out : outs)
|
|
|
- {
|
|
|
- float * data = (float *)out.data;
|
|
|
- // 遍历每个检测结果
|
|
|
- for (int i = 0; i < out.rows; i++, data += out.cols)
|
|
|
- {
|
|
|
- // 获取类别置信度
|
|
|
- cv::Mat scores = out.row(i).colRange(5, out.cols);
|
|
|
- cv::Point classIdPoint;
|
|
|
- double confidence;
|
|
|
-
|
|
|
- // 找到最大置信度对应的类别
|
|
|
- cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
|
|
|
-
|
|
|
- // 过滤低置信度结果
|
|
|
- if (confidence > CONF_THRESHOLD)
|
|
|
- {
|
|
|
- // 解析检测框坐标(YOLO输出的是相对坐标,需转换为绝对坐标)
|
|
|
- int centerX = (int)(data[0] * image.cols);
|
|
|
- int centerY = (int)(data[1] * image.rows);
|
|
|
- int width = (int)(data[2] * image.cols);
|
|
|
- int height = (int)(data[3] * image.rows);
|
|
|
-
|
|
|
- // 计算检测框左上角坐标
|
|
|
- int left = centerX - width / 2;
|
|
|
- int top = centerY - height / 2;
|
|
|
-
|
|
|
- // 保存结果
|
|
|
- boxes.push_back(cv::Rect(left, top, width, height));
|
|
|
- classIds.push_back(classIdPoint.x);
|
|
|
- confidences.push_back((float)confidence);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // -------------------------- 6. 非极大值抑制(NMS) --------------------------
|
|
|
- std::vector<int> indices;
|
|
|
- cv::dnn::NMSBoxes(boxes, confidences, CONF_THRESHOLD, NMS_THRESHOLD, indices);
|
|
|
-
|
|
|
- // 提取NMS后的结果
|
|
|
- std::vector<cv::Rect> finalBoxes;
|
|
|
- std::vector<int> finalClassIds;
|
|
|
- std::vector<float> finalConfidences;
|
|
|
- for (int idx : indices)
|
|
|
- {
|
|
|
- finalBoxes.push_back(boxes[idx]);
|
|
|
- finalClassIds.push_back(classIds[idx]);
|
|
|
- finalConfidences.push_back(confidences[idx]);
|
|
|
- }
|
|
|
-
|
|
|
- // -------------------------- 7. 绘制并显示结果 --------------------------
|
|
|
- drawDetection(image, finalBoxes, finalClassIds, finalConfidences);
|
|
|
-
|
|
|
- // 显示检测结果
|
|
|
- cv::imshow("YOLO Detection Result", image);
|
|
|
- // 保存检测结果
|
|
|
- cv::imwrite("result.jpg", image);
|
|
|
-
|
|
|
- cv::waitKey(0);
|
|
|
- cv::destroyAllWindows();
|
|
|
-}
|
|
|
-
|
|
|
-// 绘制检测结果
|
|
|
-void YoloFeatureManager::drawDetection(cv::Mat & img, const std::vector<cv::Rect> & boxes, const std::vector<int> & classIds,
|
|
|
- const std::vector<float> & confidences)
|
|
|
-{
|
|
|
- // 生成随机颜色(每个类别一种颜色)
|
|
|
- std::vector<cv::Scalar> colors;
|
|
|
- srand(time(0));
|
|
|
- for (std::size_t i = 0; i < FRUIT_VEGETABLE_COUNT; i++)
|
|
|
- {
|
|
|
- int r = rand() % 256;
|
|
|
- int g = rand() % 256;
|
|
|
- int b = rand() % 256;
|
|
|
- colors.push_back(cv::Scalar(r, g, b));
|
|
|
- }
|
|
|
-
|
|
|
- // 绘制每个检测框
|
|
|
- for (size_t i = 0; i < boxes.size(); i++)
|
|
|
- {
|
|
|
- cv::Rect box = boxes[i];
|
|
|
- // 绘制矩形框
|
|
|
- cv::rectangle(img, box, colors[classIds[i]], 2);
|
|
|
-
|
|
|
- // 构造标签文本(类别 + 置信度)
|
|
|
- std::string label = FRUIT_VEGETABLE_NAMES[classIds[i]] + ": " + std::to_string(confidences[i]).substr(0, 4);
|
|
|
- int baseLine;
|
|
|
- cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
|
|
|
-
|
|
|
- // 绘制标签背景
|
|
|
- cv::rectangle(img, cv::Point(box.x, box.y - labelSize.height),
|
|
|
- cv::Point(box.x + labelSize.width, box.y + baseLine),
|
|
|
- colors[classIds[i]], cv::FILLED);
|
|
|
-
|
|
|
- // 绘制标签文本
|
|
|
- cv::putText(img, label, cv::Point(box.x, box.y), cv::FONT_HERSHEY_SIMPLEX,
|
|
|
- 0.5, cv::Scalar(255, 255, 255), 1);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
std::string YoloFeatureManager::Class(cv::Mat & image)
|
|
|
{
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
+
|
|
|
try
|
|
|
{
|
|
|
std::string className = "";
|