#include #include #include #include #include #include namespace migraphxSamples { DetectorYOLOV9::DetectorYOLOV9() { } DetectorYOLOV9::~DetectorYOLOV9() { configurationFile.release(); } ErrorCode DetectorYOLOV9::Initialize(InitializationParameterOfDetector initializationParameterOfDetector, bool dynamic) { // 读取配置文件 std::string configFilePath = initializationParameterOfDetector.configFilePath; if (Exists(configFilePath) == false) { LOG_ERROR(stdout, "no configuration file!\n"); return CONFIG_FILE_NOT_EXIST; } if (!configurationFile.open(configFilePath, cv::FileStorage::READ)) { LOG_ERROR(stdout, "fail to open configuration file\n"); return FAIL_TO_OPEN_CONFIG_FILE; } LOG_INFO(stdout, "succeed to open configuration file\n"); // 获取配置文件参数 cv::FileNode netNode = configurationFile["DetectorYOLOV9"]; if (dynamic) { modelPath = (std::string)netNode["ModelPathDynamic"]; } else { modelPath = (std::string)netNode["ModelPathStatic"]; } std::string pathOfClassNameFile = (std::string)netNode["ClassNameFile"]; yolov9Parameter.confidenceThreshold = (float)netNode["ConfidenceThreshold"]; yolov9Parameter.nmsThreshold = (float)netNode["NMSThreshold"]; yolov9Parameter.numberOfClasses = (int)netNode["NumberOfClasses"]; useFP16 = (bool)(int)netNode["UseFP16"]; if (dynamic) { // 加载模型 if (Exists(modelPath) == false) { LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str()); return MODEL_NOT_EXIST; } migraphx::onnx_options onnx_options; onnx_options.map_input_dims["images"] = {1, 3, 1024, 1024}; net = migraphx::parse_onnx(modelPath, onnx_options); LOG_INFO(stdout, "succeed to load model: %s\n", GetFileName(modelPath).c_str()); // 获取模型输入/输出节点信息 std::cout << "inputs:" << std::endl; std::unordered_map inputs = net.get_inputs(); for (auto i : inputs) { std::cout << i.first << ":" << i.second << std::endl; } std::cout << "outputs:" << std::endl; std::unordered_map outputs = net.get_outputs(); for (auto i : outputs) { std::cout << i.first << ":" << i.second << std::endl; } inputName = inputs.begin()->first; inputShape = inputs.begin()->second; int N = inputShape.lens()[0]; int C = inputShape.lens()[1]; int H = inputShape.lens()[2]; int W = inputShape.lens()[3]; inputSize = cv::Size(W, H); // log LOG_INFO(stdout, "InputMaxSize:%dx%d\n", inputSize.width, inputSize.height); } else { // 加载模型 if (Exists(modelPath) == false) { LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str()); return MODEL_NOT_EXIST; } net = migraphx::parse_onnx(modelPath); LOG_INFO(stdout, "succeed to load model: %s\n", GetFileName(modelPath).c_str()); // 获取模型输入/输出节点信息 std::cout << "inputs:" << std::endl; std::unordered_map inputs = net.get_inputs(); for (auto i : inputs) { std::cout << i.first << ":" << i.second << std::endl; } std::cout << "outputs:" << std::endl; std::unordered_map outputs = net.get_outputs(); for (auto i : outputs) { std::cout << i.first << ":" << i.second << std::endl; } inputName = inputs.begin()->first; inputShape = inputs.begin()->second; int N = inputShape.lens()[0]; int C = inputShape.lens()[1]; int H = inputShape.lens()[2]; int W = inputShape.lens()[3]; inputSize = cv::Size(W, H); // log LOG_INFO(stdout, "InputSize:%dx%d\n", inputSize.width, inputSize.height); } LOG_INFO(stdout, "InputName:%s\n", inputName.c_str()); LOG_INFO(stdout, "ConfidenceThreshold:%f\n", yolov9Parameter.confidenceThreshold); LOG_INFO(stdout, "NMSThreshold:%f\n", yolov9Parameter.nmsThreshold); LOG_INFO(stdout, "NumberOfClasses:%d\n", yolov9Parameter.numberOfClasses); // 设置模型为GPU模式 migraphx::target gpuTarget = migraphx::gpu::target{}; // 量化 if (useFP16) { migraphx::quantize_fp16(net); } // 编译模型 migraphx::compile_options options; options.device_id = 0; options.offload_copy = true; net.compile(gpuTarget, options); LOG_INFO(stdout, "succeed to compile model: %s\n", GetFileName(modelPath).c_str()); // warm up std::unordered_map inputData; inputData[inputName] = migraphx::argument{inputShape}; net.eval(inputData); // 读取类别名 if (!pathOfClassNameFile.empty()) { std::ifstream classNameFile(pathOfClassNameFile); std::string line; while (getline(classNameFile, line)) { classNames.push_back(line); } } else { classNames.resize(yolov9Parameter.numberOfClasses); } return SUCCESS; } ErrorCode DetectorYOLOV9::Detect(const cv::Mat &srcImage, std::vector &relInputShape, std::vector &resultsOfDetection, bool dynamic) { if (srcImage.empty() || srcImage.type() != CV_8UC3) { LOG_ERROR(stdout, "image error!\n"); return IMAGE_ERROR; } // 数据预处理并转换为NCHW格式 inputSize = cv::Size(relInputShape[3], relInputShape[2]); cv::Mat inputBlob; cv::dnn::blobFromImage(srcImage, inputBlob, 1 / 255.0, inputSize, cv::Scalar(0, 0, 0), true, false); // 创建输入数据 migraphx::parameter_map inputData; if (dynamic) { inputData[inputName] = migraphx::argument{migraphx::shape(inputShape.type(), relInputShape), (float *)inputBlob.data}; } else { inputData[inputName] = migraphx::argument{inputShape, (float *)inputBlob.data}; } // 推理 std::vector inferenceResults = net.eval(inputData); // 获取推理结果 std::vector outs; migraphx::argument result = inferenceResults[0]; // 转换为cv::Mat migraphx::shape outputShape = result.get_shape(); int shape[] = {outputShape.lens()[0], outputShape.lens()[1], outputShape.lens()[2]}; cv::Mat out(3, shape, CV_32F); memcpy(out.data, result.data(), sizeof(float) * outputShape.elements()); outs.push_back(out); // 获取先验框的个数 // yolov5 has an output of shape (batchSize, 25200, 85) (Num classes + box[x,y,w,h] + confidence[c]) // yolov9 has an output of shape (batchSize, 84, 8400) (Num classes + box[x,y,w,h]) int numProposal = outs[0].size[2]; int numOut = outs[0].size[1]; // 变换输出的维度 outs[0] = outs[0].reshape(1, numOut); cv::transpose(outs[0], outs[0]); float *data = (float *)outs[0].data; // 生成先验框 std::vector confidences; std::vector boxes; std::vector classIds; float ratioh = (float)srcImage.rows / inputSize.height, ratiow = (float)srcImage.cols / inputSize.width; // 计算x,y,w,h for (int n = 0; n < numProposal; n++) { float *classes_scores = data + 4; cv::Mat scores(1, classNames.size(), CV_32FC1, classes_scores); cv::Point class_id; double maxClassScore; cv::minMaxLoc(scores, 0, &maxClassScore, 0, &class_id); if (maxClassScore > yolov9Parameter.confidenceThreshold) { confidences.push_back(maxClassScore); classIds.push_back(class_id.x); float x = data[0]; float y = data[1]; float w = data[2]; float h = data[3]; int left = int((x - 0.5 * w) * ratiow); int top = int((y - 0.5 * h) * ratioh); int width = int(w * ratiow); int height = int(h * ratioh); boxes.push_back(cv::Rect(left, top, width, height)); } data += numOut; } // 执行non maximum suppression消除冗余重叠boxes std::vector indices; cv::dnn::NMSBoxes(boxes, confidences, yolov9Parameter.confidenceThreshold, yolov9Parameter.nmsThreshold, indices); for (size_t i = 0; i < indices.size(); ++i) { int idx = indices[i]; int classID = classIds[idx]; string className = classNames[classID]; float confidence = confidences[idx]; cv::Rect box = boxes[idx]; ResultOfDetection result; result.boundingBox = box; result.confidence = confidence; // confidence result.classID = classID; // label result.className = className; resultsOfDetection.push_back(result); } return SUCCESS; } }