YOLOV5.cpp 9.57 KB
Newer Older
liucong's avatar
liucong committed
1
#include <YOLOV5.h>
Your Name's avatar
Your Name committed
2
3
4
5
6
7
8
9
10
#include <migraphx/onnx.hpp>
#include <migraphx/gpu/target.hpp>
#include <migraphx/quantization.hpp>
#include <Filesystem.h>
#include <SimpleLog.h>

namespace migraphxSamples
{

liucong's avatar
liucong committed
11
DetectorYOLOV5::DetectorYOLOV5() {}
Your Name's avatar
Your Name committed
12

liucong's avatar
liucong committed
13
DetectorYOLOV5::~DetectorYOLOV5() { configurationFile.release(); }
Your Name's avatar
Your Name committed
14

liucong's avatar
liucong committed
15
16
17
ErrorCode
DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializationParameterOfDetector,
                           bool dynamic)
Your Name's avatar
Your Name committed
18
{
liucong's avatar
liucong committed
19
    // 读取配置文件
liucong's avatar
liucong committed
20
    std::string configFilePath = initializationParameterOfDetector.configFilePath;
liucong's avatar
liucong committed
21
    if(!Exists(configFilePath))
Your Name's avatar
Your Name committed
22
    {
liucong's avatar
liucong committed
23
24
        LOG_ERROR(stdout, "no configuration file!\n");
        return CONFIG_FILE_NOT_EXIST;
Your Name's avatar
Your Name committed
25
    }
liucong's avatar
liucong committed
26
27
    if(!configurationFile.open(configFilePath, cv::FileStorage::READ))
    {
liucong's avatar
liucong committed
28
29
        LOG_ERROR(stdout, "fail to open configuration file\n");
        return FAIL_TO_OPEN_CONFIG_FILE;
liucong's avatar
liucong committed
30
31
    }
    LOG_INFO(stdout, "succeed to open configuration file\n");
liucong's avatar
liucong committed
32

Your Name's avatar
Your Name committed
33
    // 获取配置文件参数
liucong's avatar
liucong committed
34
    cv::FileNode netNode = configurationFile["DetectorYOLOV5"];
shizhm's avatar
shizhm committed
35
36
    if(dynamic)
    {
liucong's avatar
liucong committed
37
        modelPath = (std::string)netNode["ModelPathDynamic"];
shizhm's avatar
shizhm committed
38
39
40
    }
    else
    {
liucong's avatar
liucong committed
41
        modelPath = (std::string)netNode["ModelPathStatic"];
shizhm's avatar
shizhm committed
42
    }
liucong's avatar
liucong committed
43
    std::string pathOfClassNameFile     = (std::string)netNode["ClassNameFile"];
Your Name's avatar
Your Name committed
44
    yolov5Parameter.confidenceThreshold = (float)netNode["ConfidenceThreshold"];
liucong's avatar
liucong committed
45
46
47
48
    yolov5Parameter.nmsThreshold        = (float)netNode["NMSThreshold"];
    yolov5Parameter.objectThreshold     = (float)netNode["ObjectThreshold"];
    yolov5Parameter.numberOfClasses     = (int)netNode["NumberOfClasses"];
    useFP16                             = (bool)(int)netNode["UseFP16"];
Your Name's avatar
Your Name committed
49

shizhm's avatar
shizhm committed
50
    if(dynamic)
Your Name's avatar
Your Name committed
51
    {
shizhm's avatar
shizhm committed
52
        // 加载模型
liucong's avatar
liucong committed
53
        if(!Exists(modelPath))
shizhm's avatar
shizhm committed
54
        {
liucong's avatar
liucong committed
55
            LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str());
shizhm's avatar
shizhm committed
56
57
            return MODEL_NOT_EXIST;
        }
liucong's avatar
liucong committed
58

shizhm's avatar
shizhm committed
59
        migraphx::onnx_options onnx_options;
liucong's avatar
liucong committed
60
61
62
        onnx_options.map_input_dims["images"] = {1, 3, 800, 800};
        net                                   = migraphx::parse_onnx(modelPath, onnx_options);
        LOG_INFO(stdout, "succeed to load model: %s\n", GetFileName(modelPath).c_str());
shizhm's avatar
shizhm committed
63

liucong's avatar
liucong committed
64
        // 获取模型输入/输出节点信息
liucong's avatar
liucong committed
65
66
67
68
69
70
71
72
73
        std::unordered_map<std::string, migraphx::shape> inputs  = net.get_inputs();
        std::unordered_map<std::string, migraphx::shape> outputs = net.get_outputs();
        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);
shizhm's avatar
shizhm committed
74
75

        // log
liucong's avatar
liucong committed
76
        LOG_INFO(stdout, "InputMaxSize:%dx%d\n", inputSize.width, inputSize.height);
Your Name's avatar
Your Name committed
77
    }
shizhm's avatar
shizhm committed
78
79
    else
    {
shizhm's avatar
shizhm committed
80
        // 加载模型
liucong's avatar
liucong committed
81
        if(!Exists(modelPath))
shizhm's avatar
shizhm committed
82
        {
liucong's avatar
liucong committed
83
            LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str());
shizhm's avatar
shizhm committed
84
85
            return MODEL_NOT_EXIST;
        }
shizhm's avatar
shizhm committed
86
        net = migraphx::parse_onnx(modelPath);
liucong's avatar
liucong committed
87
        LOG_INFO(stdout, "succeed to load model: %s\n", GetFileName(modelPath).c_str());
shizhm's avatar
shizhm committed
88

liucong's avatar
liucong committed
89
        // 获取模型输入/输出节点信息
liucong's avatar
liucong committed
90
91
92
93
94
95
96
97
98
        std::unordered_map<std::string, migraphx::shape> inputs  = net.get_inputs();
        std::unordered_map<std::string, migraphx::shape> outputs = net.get_outputs();
        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);
shizhm's avatar
shizhm committed
99
100

        // log
liucong's avatar
liucong committed
101
        LOG_INFO(stdout, "InputSize:%dx%d\n", inputSize.width, inputSize.height);
shizhm's avatar
shizhm committed
102
103
    }

liucong's avatar
liucong committed
104
105
106
107
108
    LOG_INFO(stdout, "InputName:%s\n", inputName.c_str());
    LOG_INFO(stdout, "ConfidenceThreshold:%f\n", yolov5Parameter.confidenceThreshold);
    LOG_INFO(stdout, "NMSThreshold:%f\n", yolov5Parameter.nmsThreshold);
    LOG_INFO(stdout, "objectThreshold:%f\n", yolov5Parameter.objectThreshold);
    LOG_INFO(stdout, "NumberOfClasses:%d\n", yolov5Parameter.numberOfClasses);
Your Name's avatar
Your Name committed
109
110
111
112

    // 设置模型为GPU模式
    migraphx::target gpuTarget = migraphx::gpu::target{};

liucong's avatar
liucong committed
113
    // 量化
Your Name's avatar
Your Name committed
114
115
116
117
118
119
120
    if(useFP16)
    {
        migraphx::quantize_fp16(net);
    }

    // 编译模型
    migraphx::compile_options options;
liucong's avatar
liucong committed
121
122
123
124
    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());
Your Name's avatar
Your Name committed
125

liucong's avatar
liucong committed
126
127
    // warm up
    std::unordered_map<std::string, migraphx::argument> inputData;
liucong's avatar
liucong committed
128
    inputData[inputName] = migraphx::argument{inputShape};
Your Name's avatar
Your Name committed
129
130
131
132
133
    net.eval(inputData);

    // 读取类别名
    if(!pathOfClassNameFile.empty())
    {
liucong's avatar
liucong committed
134
135
        std::ifstream classNameFile(pathOfClassNameFile);
        std::string line;
liucong's avatar
liucong committed
136
        while(getline(classNameFile, line))
Your Name's avatar
Your Name committed
137
138
139
140
141
142
143
144
145
146
147
148
        {
            classNames.push_back(line);
        }
    }
    else
    {
        classNames.resize(yolov5Parameter.numberOfClasses);
    }

    return SUCCESS;
}

liucong's avatar
liucong committed
149
150
151
152
ErrorCode DetectorYOLOV5::Detect(const cv::Mat& srcImage,
                                 std::vector<std::size_t>& relInputShape,
                                 std::vector<ResultOfDetection>& resultsOfDetection,
                                 bool dynamic)
Your Name's avatar
Your Name committed
153
{
liucong's avatar
liucong committed
154
    if(srcImage.empty() || srcImage.type() != CV_8UC3)
Your Name's avatar
Your Name committed
155
    {
liucong's avatar
liucong committed
156
        LOG_ERROR(stdout, "image error!\n");
Your Name's avatar
Your Name committed
157
158
159
        return IMAGE_ERROR;
    }

shizhm's avatar
shizhm committed
160
161
    // 数据预处理并转换为NCHW格式
    inputSize = cv::Size(relInputShape[3], relInputShape[2]);
Your Name's avatar
Your Name committed
162
    cv::Mat inputBlob;
liucong's avatar
liucong committed
163
164
    cv::dnn::blobFromImage(
        srcImage, inputBlob, 1 / 255.0, inputSize, cv::Scalar(0, 0, 0), true, false);
liucong's avatar
liucong committed
165
166

    // 创建输入数据
167
    migraphx::parameter_map inputData;
shizhm's avatar
shizhm committed
168
169
    if(dynamic)
    {
liucong's avatar
liucong committed
170
171
        inputData[inputName] = migraphx::argument{migraphx::shape(inputShape.type(), relInputShape),
                                                  (float*)inputBlob.data};
shizhm's avatar
shizhm committed
172
173
174
    }
    else
    {
liucong's avatar
liucong committed
175
        inputData[inputName] = migraphx::argument{inputShape, (float*)inputBlob.data};
shizhm's avatar
shizhm committed
176
    }
shizhm's avatar
shizhm committed
177

Your Name's avatar
Your Name committed
178
179
180
181
182
    // 推理
    std::vector<migraphx::argument> inferenceResults = net.eval(inputData);

    // 获取推理结果
    std::vector<cv::Mat> outs;
liucong's avatar
liucong committed
183
    migraphx::argument result = inferenceResults[0];
Your Name's avatar
Your Name committed
184
185
186

    // 转换为cv::Mat
    migraphx::shape outputShape = result.get_shape();
liucong's avatar
liucong committed
187
188
189
    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());
Your Name's avatar
Your Name committed
190
191
    outs.push_back(out);

liucong's avatar
liucong committed
192
    // 获取先验框的个数
Your Name's avatar
Your Name committed
193
    int numProposal = outs[0].size[1];
liucong's avatar
liucong committed
194
195
    int numOut      = outs[0].size[2];
    // 变换输出的维度
Your Name's avatar
Your Name committed
196
197
    outs[0] = outs[0].reshape(0, numProposal);

liucong's avatar
liucong committed
198
    // 生成先验框
Your Name's avatar
Your Name committed
199
200
201
    std::vector<float> confidences;
    std::vector<cv::Rect> boxes;
    std::vector<int> classIds;
liucong's avatar
liucong committed
202
203
    float ratioh = (float)srcImage.rows / inputSize.height,
          ratiow = (float)srcImage.cols / inputSize.width;
Your Name's avatar
Your Name committed
204

liucong's avatar
liucong committed
205
    // 计算cx,cy,w,h,box_sore,class_sore
Your Name's avatar
Your Name committed
206
207
    int n = 0, rowInd = 0;
    float* pdata = (float*)outs[0].data;
liucong's avatar
liucong committed
208
    for(n = 0; n < numProposal; n++)
Your Name's avatar
Your Name committed
209
210
    {
        float boxScores = pdata[4];
liucong's avatar
liucong committed
211
        if(boxScores > yolov5Parameter.objectThreshold)
Your Name's avatar
Your Name committed
212
213
214
215
216
217
        {
            cv::Mat scores = outs[0].row(rowInd).colRange(5, numOut);
            cv::Point classIdPoint;
            double maxClassScore;
            cv::minMaxLoc(scores, 0, &maxClassScore, 0, &classIdPoint);
            maxClassScore *= boxScores;
liucong's avatar
liucong committed
218
            if(maxClassScore > yolov5Parameter.confidenceThreshold)
Your Name's avatar
Your Name committed
219
220
            {
                const int classIdx = classIdPoint.x;
liucong's avatar
liucong committed
221
222
223
224
                float cx           = pdata[0] * ratiow;
                float cy           = pdata[1] * ratioh;
                float w            = pdata[2] * ratiow;
                float h            = pdata[3] * ratioh;
Your Name's avatar
Your Name committed
225
226

                int left = int(cx - 0.5 * w);
liucong's avatar
liucong committed
227
                int top  = int(cy - 0.5 * h);
Your Name's avatar
Your Name committed
228
229
230
231
232
233
234
235
236
237

                confidences.push_back((float)maxClassScore);
                boxes.push_back(cv::Rect(left, top, (int)(w), (int)(h)));
                classIds.push_back(classIdx);
            }
        }
        rowInd++;
        pdata += numOut;
    }

liucong's avatar
liucong committed
238
    // 执行non maximum suppression消除冗余重叠boxes
Your Name's avatar
Your Name committed
239
    std::vector<int> indices;
liucong's avatar
liucong committed
240
241
242
243
244
245
    cv::dnn::NMSBoxes(boxes,
                      confidences,
                      yolov5Parameter.confidenceThreshold,
                      yolov5Parameter.nmsThreshold,
                      indices);
    for(size_t i = 0; i < indices.size(); ++i)
Your Name's avatar
Your Name committed
246
    {
liucong's avatar
liucong committed
247
248
249
250
251
        int idx          = indices[i];
        int classID      = classIds[idx];
        string className = classNames[classID];
        float confidence = confidences[idx];
        cv::Rect box     = boxes[idx];
Your Name's avatar
Your Name committed
252
253

        ResultOfDetection result;
liucong's avatar
liucong committed
254
255
256
257
        result.boundingBox = box;
        result.confidence  = confidence; // confidence
        result.classID     = classID;    // label
        result.className   = className;
Your Name's avatar
Your Name committed
258
259
260
261
262
263
        resultsOfDetection.push_back(result);
    }

    return SUCCESS;
}

liucong's avatar
liucong committed
264
} // namespace migraphxSamples