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

namespace migraphxSamples
{

liucong's avatar
liucong committed
12
13
#define SSD_QUANT_BASE 4096 // 基数
#define SSD_COORDI_NUM 4    // 坐标个数(x1,y1,x2,y2)
Your Name's avatar
Your Name committed
14
#define SSD_PROPOSAL_WIDTH 6
liucong's avatar
liucong committed
15
#define SSD_HALF 0.5
Your Name's avatar
Your Name committed
16
17
#define SSD_ASPECT_RATIO_NUM 6 // 默认最大的宽高比个数

liucong's avatar
liucong committed
18
19
#define SSD_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define SSD_MIN(a, b) (((a) < (b)) ? (a) : (b))
Your Name's avatar
Your Name committed
20
21
22

// 16字节对齐
#define SSD_ALIGN_16 16
liucong's avatar
liucong committed
23
#define SSD_ALIGN16(number) ((number + SSD_ALIGN_16 - 1) / SSD_ALIGN_16 * SSD_ALIGN_16)
Your Name's avatar
Your Name committed
24

liucong's avatar
liucong committed
25
DetectorRetinaFace::DetectorRetinaFace() {}
Your Name's avatar
Your Name committed
26
27
28
29

DetectorRetinaFace::~DetectorRetinaFace()
{
    configurationFile.release();
liucong's avatar
liucong committed
30

Your Name's avatar
Your Name committed
31
32
33
34
    // 释放SSD参数的内存空间
    delete[] ssdParameter.buffer;
}

liucong's avatar
liucong committed
35
36
ErrorCode
DetectorRetinaFace::Initialize(InitializationParameterOfDetector initializationParameterOfDetector)
Your Name's avatar
Your Name committed
37
{
liucong's avatar
liucong committed
38
    // 读取配置文件
liucong's avatar
liucong committed
39
    std::string configFilePath = initializationParameterOfDetector.configFilePath;
liucong's avatar
liucong committed
40
    if(!Exists(configFilePath))
Your Name's avatar
Your Name committed
41
    {
liucong's avatar
liucong committed
42
43
44
45
46
        LOG_ERROR(stdout, "no configuration file!\n");
        return CONFIG_FILE_NOT_EXIST;
    }
    if(!configurationFile.open(configFilePath, cv::FileStorage::READ))
    {
liucong's avatar
liucong committed
47
48
        LOG_ERROR(stdout, "fail to open configuration file\n");
        return FAIL_TO_OPEN_CONFIG_FILE;
Your Name's avatar
Your Name committed
49
    }
liucong's avatar
liucong committed
50
    LOG_INFO(stdout, "succeed to open configuration file\n");
liucong's avatar
liucong committed
51

Your Name's avatar
Your Name committed
52
    // 获取配置文件参数
liucong's avatar
liucong committed
53
    cv::FileNode netNode = configurationFile["DetectorRetinaFace"];
liucong's avatar
liucong committed
54
55
56
57
58
59
60
61
62
    string modelPath     = (string)netNode["ModelPath"];
    scale                = (float)netNode["Scale"];
    meanValue.val[0]     = (float)netNode["MeanValue1"];
    meanValue.val[1]     = (float)netNode["MeanValue2"];
    meanValue.val[2]     = (float)netNode["MeanValue3"];
    swapRB               = (bool)(int)netNode["SwapRB"];
    crop                 = (bool)(int)netNode["Crop"];
    useInt8              = (bool)(int)netNode["UseInt8"];
    useFP16              = (bool)(int)netNode["UseFP16"];
Your Name's avatar
Your Name committed
63
64

    // 加载模型
liucong's avatar
liucong committed
65
    if(!Exists(modelPath))
Your Name's avatar
Your Name committed
66
    {
liucong's avatar
liucong committed
67
        LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str());
Your Name's avatar
Your Name committed
68
69
70
        return MODEL_NOT_EXIST;
    }
    net = migraphx::parse_onnx(modelPath);
liucong's avatar
liucong committed
71
    LOG_INFO(stdout, "succeed to load model: %s\n", GetFileName(modelPath).c_str());
Your Name's avatar
Your Name committed
72

liucong's avatar
liucong committed
73
    // 获取模型输入/输出节点信息
liucong's avatar
liucong committed
74
75
76
77
78
79
80
81
82
83
    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);

Your Name's avatar
Your Name committed
84
85
86
87
88
89
90
    // 设置模型为GPU模式
    migraphx::target gpuTarget = migraphx::gpu::target{};

    // 量化
    if(useInt8)
    {
        // 创建量化校准数据,建议使用测试集中的多张典型图像
liucong's avatar
liucong committed
91
        cv::Mat srcImage = cv::imread("../Resource/Images/FaceDetect_2.jpg", 1);
Your Name's avatar
Your Name committed
92
        std::vector<cv::Mat> srcImages;
liucong's avatar
liucong committed
93
        for(int i = 0; i < inputShape.lens()[0]; ++i)
Your Name's avatar
Your Name committed
94
95
96
        {
            srcImages.push_back(srcImage);
        }
liucong's avatar
liucong committed
97

Your Name's avatar
Your Name committed
98
        cv::Mat inputBlob;
liucong's avatar
liucong committed
99
        cv::dnn::blobFromImages(srcImages, inputBlob, scale, inputSize, meanValue, swapRB, false);
liucong's avatar
liucong committed
100

liucong's avatar
liucong committed
101
        std::unordered_map<std::string, migraphx::argument> inputData;
liucong's avatar
liucong committed
102
103
104
        inputData[inputName] = migraphx::argument{inputShape, (float*)inputBlob.data};
        std::vector<std::unordered_map<std::string, migraphx::argument>> calibrationData = {
            inputData};
Your Name's avatar
Your Name committed
105
106
107
108

        // INT8量化
        migraphx::quantize_int8(net, gpuTarget, calibrationData);
    }
liucong's avatar
liucong committed
109
    else if(useFP16)
Your Name's avatar
Your Name committed
110
111
112
113
114
115
    {
        migraphx::quantize_fp16(net);
    }

    // 编译模型
    migraphx::compile_options options;
liucong's avatar
liucong committed
116
117
118
119
    options.device_id    = 0; // 设置GPU设备,默认为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
120

liucong's avatar
liucong committed
121
122
    // warm up
    std::unordered_map<std::string, migraphx::argument> inputData;
liucong's avatar
liucong committed
123
    inputData[inputName] = migraphx::argument{inputShape};
Your Name's avatar
Your Name committed
124
125
126
    net.eval(inputData);

    // log
liucong's avatar
liucong committed
127
128
129
130
131
132
133
134
    LOG_INFO(stdout, "InputSize:%dx%d\n", inputSize.width, inputSize.height);
    LOG_INFO(stdout, "InputName:%s\n", inputName.c_str());
    LOG_INFO(stdout, "Scale:%.6f\n", scale);
    LOG_INFO(stdout, "Mean:%.2f,%.2f,%.2f\n", meanValue.val[0], meanValue.val[1], meanValue.val[2]);
    LOG_INFO(stdout, "SwapRB:%d\n", (int)swapRB);
    LOG_INFO(stdout, "Crop:%d\n", (int)crop);
    LOG_INFO(stdout, "UseInt8:%d\n", (int)useInt8);
    LOG_INFO(stdout, "UseFP16:%d\n", (int)useFP16);
Your Name's avatar
Your Name committed
135
136
137
138
139
140
141

    // 读取SSD 参数
    GetSSDParameter();

    return SUCCESS;
}

liucong's avatar
liucong committed
142
143
ErrorCode DetectorRetinaFace::Detect(const cv::Mat& srcImage,
                                     std::vector<ResultOfDetection>& resultsOfDetection)
Your Name's avatar
Your Name committed
144
145
{

liucong's avatar
liucong committed
146
    if(srcImage.empty() || srcImage.type() != CV_8UC3)
Your Name's avatar
Your Name committed
147
    {
liucong's avatar
liucong committed
148
        LOG_ERROR(stdout, "image error!\n");
Your Name's avatar
Your Name committed
149
150
151
        return IMAGE_ERROR;
    }

liucong's avatar
liucong committed
152
    // 数据预处理并转换为NCHW格式
Your Name's avatar
Your Name committed
153
    cv::Mat inputBlob;
liucong's avatar
liucong committed
154
155
    cv::dnn::blobFromImage(srcImage, inputBlob, scale, inputSize, meanValue, swapRB, false);

liucong's avatar
liucong committed
156
157
    // 创建输入数据
    std::unordered_map<std::string, migraphx::argument> inputData;
liucong's avatar
liucong committed
158
    inputData[inputName] = migraphx::argument{inputShape, (float*)inputBlob.data};
Your Name's avatar
Your Name committed
159
160

    // 推理
liucong's avatar
liucong committed
161
    std::vector<migraphx::argument> inferenceResults = net.eval(inputData);
liucong's avatar
liucong committed
162
163
    std::vector<std::vector<float>> regressions;
    std::vector<std::vector<float>> classifications;
liucong's avatar
liucong committed
164
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i) // 执行Permute操作
Your Name's avatar
Your Name committed
165
    {
liucong's avatar
liucong committed
166
167
168
        int numberOfPriorBox =
            ssdParameter.detectInputChn[i] /
            (4 * (ssdParameter.priorBoxHeight[i] * ssdParameter.priorBoxWidth[i]));
Your Name's avatar
Your Name committed
169
170
171

        // BboxHead
        std::vector<float> regression;
liucong's avatar
liucong committed
172
        migraphx::argument result0 = inferenceResults[2 * i];
Your Name's avatar
Your Name committed
173
        result0.visit([&](auto output) { regression.assign(output.begin(), output.end()); });
liucong's avatar
liucong committed
174
175
176
177
        regression = PermuteLayer(regression,
                                  ssdParameter.priorBoxWidth[i],
                                  ssdParameter.priorBoxHeight[i],
                                  numberOfPriorBox * 4);
Your Name's avatar
Your Name committed
178
        regressions.push_back(regression);
liucong's avatar
liucong committed
179

Your Name's avatar
Your Name committed
180
181
        // ClassHead
        std::vector<float> classification;
liucong's avatar
liucong committed
182
        migraphx::argument result1 = inferenceResults[2 * i + 1];
Your Name's avatar
Your Name committed
183
        result1.visit([&](auto output) { classification.assign(output.begin(), output.end()); });
liucong's avatar
liucong committed
184
185
186
187
        classification = PermuteLayer(classification,
                                      ssdParameter.priorBoxWidth[i],
                                      ssdParameter.priorBoxHeight[i],
                                      numberOfPriorBox * ssdParameter.classNum);
Your Name's avatar
Your Name committed
188
189
190
191
        classifications.push_back(classification);
    }

    // 对推理结果进行处理,得到最后SSD检测的结果
liucong's avatar
liucong committed
192
    GetResult(classifications, regressions, resultsOfDetection);
Your Name's avatar
Your Name committed
193
194

    // 转换到原图坐标
liucong's avatar
liucong committed
195
    for(int i = 0; i < resultsOfDetection.size(); ++i)
Your Name's avatar
Your Name committed
196
    {
liucong's avatar
liucong committed
197
198
        float ratioOfWidth  = (1.0 * srcImage.cols) / inputSize.width;
        float ratioOfHeight = (1.0 * srcImage.rows) / inputSize.height;
Your Name's avatar
Your Name committed
199

liucong's avatar
liucong committed
200
201
202
203
        resultsOfDetection[i].boundingBox.x *= ratioOfWidth;
        resultsOfDetection[i].boundingBox.width *= ratioOfWidth;
        resultsOfDetection[i].boundingBox.y *= ratioOfHeight;
        resultsOfDetection[i].boundingBox.height *= ratioOfHeight;
Your Name's avatar
Your Name committed
204
205
206
    }

    // 按照置信度排序
liucong's avatar
liucong committed
207
    sort(resultsOfDetection.begin(), resultsOfDetection.end(), CompareConfidence);
Your Name's avatar
Your Name committed
208
209
210
211
212
213

    return SUCCESS;
}

void DetectorRetinaFace::GetSSDParameter()
{
liucong's avatar
liucong committed
214
215
    cv::FileNode rootNode              = configurationFile["DetectorRetinaFace"];
    ssdParameter.numberOfPriorBoxLayer = (int)rootNode["PriorBoxLayerNumber"];
Your Name's avatar
Your Name committed
216
217

    ssdParameter.srcImageHeight = inputSize.height;
liucong's avatar
liucong committed
218
    ssdParameter.srcImageWidth  = inputSize.width;
Your Name's avatar
Your Name committed
219
220
221
222

    // MinSize,MaxSize
    ssdParameter.priorBoxMinSize.resize(ssdParameter.numberOfPriorBoxLayer);
    ssdParameter.priorBoxMaxSize.resize(ssdParameter.numberOfPriorBoxLayer);
liucong's avatar
liucong committed
223
224
225
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
    {
        char nodeName[256] = {0};
Your Name's avatar
Your Name committed
226

liucong's avatar
liucong committed
227
        // miniSize
Your Name's avatar
Your Name committed
228
        {
liucong's avatar
liucong committed
229
            int j = 0;
Your Name's avatar
Your Name committed
230
231
            while(true)
            {
liucong's avatar
liucong committed
232
233
234
235
236
237
238
239
240
241
                sprintf(nodeName, "MinSize%d%d", (i + 1), ++j);
                cv::FileNode miniSizeNode = rootNode[nodeName];
                if(miniSizeNode.empty())
                {
                    break;
                }
                else
                {
                    ssdParameter.priorBoxMinSize[i].push_back((float)rootNode[nodeName]);
                }
Your Name's avatar
Your Name committed
242
243
244
            }
        }

liucong's avatar
liucong committed
245
        // maxSize
Your Name's avatar
Your Name committed
246
        {
liucong's avatar
liucong committed
247
            int j = 0;
Your Name's avatar
Your Name committed
248
249
            while(true)
            {
liucong's avatar
liucong committed
250
251
252
253
254
255
256
257
258
259
                sprintf(nodeName, "MaxSize%d%d", (i + 1), ++j);
                cv::FileNode maxSizeNode = rootNode[nodeName];
                if(maxSizeNode.empty())
                {
                    break;
                }
                else
                {
                    ssdParameter.priorBoxMaxSize[i].push_back((float)rootNode[nodeName]);
                }
Your Name's avatar
Your Name committed
260
261
            }
        }
liucong's avatar
liucong committed
262
    }
Your Name's avatar
Your Name committed
263
264

    // MinSizeNumber,MaxSizeNumber
liucong's avatar
liucong committed
265
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
Your Name's avatar
Your Name committed
266
267
    {
        ssdParameter.minSizeNum[i] = ssdParameter.priorBoxMinSize[i].size();
liucong's avatar
liucong committed
268
269
        ssdParameter.maxSizeNum[i] = ssdParameter.priorBoxMaxSize[i].size();
        ;
Your Name's avatar
Your Name committed
270
271
272
    }

    // Flip,Clip
liucong's avatar
liucong committed
273
274
275
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
    {
        char nodeName[256] = {0};
Your Name's avatar
Your Name committed
276

liucong's avatar
liucong committed
277
278
279
280
        // Flip
        sprintf(nodeName, "Flip%d", i + 1);
        int flip             = (int)rootNode[nodeName];
        ssdParameter.flip[i] = flip;
Your Name's avatar
Your Name committed
281

liucong's avatar
liucong committed
282
283
284
285
286
        // Clip
        sprintf(nodeName, "Clip%d", i + 1);
        int clip             = (int)rootNode[nodeName];
        ssdParameter.clip[i] = clip;
    }
Your Name's avatar
Your Name committed
287
288
289

    // AspectRatio
    ssdParameter.priorBoxAspectRatio.resize(ssdParameter.numberOfPriorBoxLayer);
liucong's avatar
liucong committed
290
291
292
293
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
    {
        char nodeName[256] = {0};
        int j              = 0;
Your Name's avatar
Your Name committed
294
295
        while(true)
        {
liucong's avatar
liucong committed
296
297
298
299
300
301
302
303
304
305
            sprintf(nodeName, "AspectRatio%d%d", (i + 1), ++j);
            cv::FileNode aspectRatioNode = rootNode[nodeName];
            if(aspectRatioNode.empty())
            {
                break;
            }
            else
            {
                ssdParameter.priorBoxAspectRatio[i].push_back((float)rootNode[nodeName]);
            }
Your Name's avatar
Your Name committed
306
307
308
309
        }
    }

    // aspect ratio number
liucong's avatar
liucong committed
310
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
Your Name's avatar
Your Name committed
311
312
313
314
315
    {
        ssdParameter.inputAspectRatioNum[i] = ssdParameter.priorBoxAspectRatio[i].size();
    }

    // PriorBoxStep
liucong's avatar
liucong committed
316
317
318
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
    {
        char nodeName[256] = {0};
Your Name's avatar
Your Name committed
319

liucong's avatar
liucong committed
320
321
322
323
        // width
        sprintf(nodeName, "PriorBoxStepWidth%d", i + 1);
        int width                         = (int)rootNode[nodeName];
        ssdParameter.priorBoxStepWidth[i] = width;
Your Name's avatar
Your Name committed
324

liucong's avatar
liucong committed
325
326
327
328
329
        // height
        sprintf(nodeName, "PriorBoxStepHeight%d", i + 1);
        int height                         = (int)rootNode[nodeName];
        ssdParameter.priorBoxStepHeight[i] = height;
    }
Your Name's avatar
Your Name committed
330
331

    // PriorBoxWidth,PriorBoxHeight
liucong's avatar
liucong committed
332
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
Your Name's avatar
Your Name committed
333
    {
liucong's avatar
liucong committed
334
335
336
337
        ssdParameter.priorBoxWidth[i] =
            ssdParameter.srcImageWidth / ssdParameter.priorBoxStepWidth[i];
        ssdParameter.priorBoxHeight[i] =
            ssdParameter.srcImageHeight / ssdParameter.priorBoxStepHeight[i];
Your Name's avatar
Your Name committed
338
339
340
341
    }

    ssdParameter.offset = (float)rootNode["Offset"];

liucong's avatar
liucong committed
342
343
344
345
    ssdParameter.priorBoxVar[0] = (int)(0.1f * SSD_QUANT_BASE);
    ssdParameter.priorBoxVar[1] = (int)(0.1f * SSD_QUANT_BASE);
    ssdParameter.priorBoxVar[2] = (int)(0.2f * SSD_QUANT_BASE);
    ssdParameter.priorBoxVar[3] = (int)(0.2f * SSD_QUANT_BASE);
Your Name's avatar
Your Name committed
346

liucong's avatar
liucong committed
347
    int classNumber              = (int)rootNode["ClassNumber"];
Your Name's avatar
Your Name committed
348
349
    ssdParameter.softMaxInHeight = classNumber;

liucong's avatar
liucong committed
350
351
    ssdParameter.concatNum        = ssdParameter.numberOfPriorBoxLayer;
    ssdParameter.softMaxOutWidth  = 1;
Your Name's avatar
Your Name committed
352
353
    ssdParameter.softMaxOutHeight = classNumber;

liucong's avatar
liucong committed
354
355
356
357
358
359
    int totalSizeOfClasReg = 0; // 分类和回归一共需要的内存空间大小
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
    {
        int priorBoxNumber = 0;
        priorBoxNumber += 1; // aspect ratio=1
        for(int j = 0; j < ssdParameter.inputAspectRatioNum[i]; j++)
Your Name's avatar
Your Name committed
360
361
        {
            ++priorBoxNumber;
liucong's avatar
liucong committed
362
            if(ssdParameter.flip[j] == 1)
Your Name's avatar
Your Name committed
363
364
365
366
367
368
            {
                ++priorBoxNumber;
            }
        }
        priorBoxNumber = ssdParameter.minSizeNum[i] * priorBoxNumber + ssdParameter.maxSizeNum[i];

liucong's avatar
liucong committed
369
370
371
372
373
        int totalPriorBoxNumber =
            priorBoxNumber * ssdParameter.priorBoxHeight[i] * ssdParameter.priorBoxWidth[i];
        ssdParameter.softMaxInChn[i] = totalPriorBoxNumber * classNumber;
        ssdParameter.softMaxOutChn += totalPriorBoxNumber;
        ssdParameter.detectInputChn[i] = totalPriorBoxNumber * 4;
Your Name's avatar
Your Name committed
374

liucong's avatar
liucong committed
375
376
        totalSizeOfClasReg += (ssdParameter.softMaxInChn[i] + ssdParameter.detectInputChn[i]);
    }
Your Name's avatar
Your Name committed
377
378
379

    // DetectionOut
    ssdParameter.classNum = classNumber;
liucong's avatar
liucong committed
380
381
382
383
384
385
386
    ssdParameter.topK     = (int)rootNode["TopK"];
    ;
    ssdParameter.keepTopK   = (int)rootNode["KeepTopK"];
    ssdParameter.NMSThresh  = (int)((float)rootNode["NMSThreshold"] * SSD_QUANT_BASE);
    ssdParameter.confThresh = (int)((float)rootNode["ConfidenceThreshold"] * SSD_QUANT_BASE);

    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; i++)
Your Name's avatar
Your Name committed
387
    {
liucong's avatar
liucong committed
388
389
390
        int numberOfPriorBox =
            ssdParameter.detectInputChn[i] /
            (4 * (ssdParameter.priorBoxHeight[i] * ssdParameter.priorBoxWidth[i]));
Your Name's avatar
Your Name committed
391

liucong's avatar
liucong committed
392
393
394
        ssdParameter.convHeight[2 * i]  = ssdParameter.priorBoxHeight[i];
        ssdParameter.convWidth[2 * i]   = ssdParameter.priorBoxWidth[i];
        ssdParameter.convChannel[2 * i] = numberOfPriorBox * 4;
Your Name's avatar
Your Name committed
395

liucong's avatar
liucong committed
396
397
398
        ssdParameter.convHeight[2 * i + 1]  = ssdParameter.priorBoxHeight[i];
        ssdParameter.convWidth[2 * i + 1]   = ssdParameter.priorBoxWidth[i];
        ssdParameter.convChannel[2 * i + 1] = numberOfPriorBox * ssdParameter.classNum;
Your Name's avatar
Your Name committed
399

liucong's avatar
liucong committed
400
401
        ssdParameter.convStride[i] =
            SSD_ALIGN16(ssdParameter.convChannel[2 * i + 1] * sizeof(int)) / sizeof(int);
Your Name's avatar
Your Name committed
402
403
404
    }

    // 计算softMaxOutputData内存空间大小
liucong's avatar
liucong committed
405
    int softMaxSize = 0;
Your Name's avatar
Your Name committed
406
407
408
409
410
411
    for(int i = 0; i < ssdParameter.concatNum; i++)
    {
        softMaxSize += ssdParameter.softMaxInChn[i];
    }

    // 计算getResultBuffer内存空间大小
liucong's avatar
liucong committed
412
    int priorNum      = 0;
Your Name's avatar
Your Name committed
413
414
415
    int detectionSize = 0;
    for(int i = 0; i < ssdParameter.concatNum; i++)
    {
liucong's avatar
liucong committed
416
        priorNum += ssdParameter.detectInputChn[i] / SSD_COORDI_NUM;
Your Name's avatar
Your Name committed
417
    }
liucong's avatar
liucong committed
418
419
420
    detectionSize += priorNum * SSD_COORDI_NUM;
    detectionSize += priorNum * SSD_PROPOSAL_WIDTH * 2;
    detectionSize += priorNum * 2;
Your Name's avatar
Your Name committed
421
422

    // 计算dstRoi,classRoiNum,dstScore内存空间大小
liucong's avatar
liucong committed
423
424
    int dstRoiSize      = 0;
    int dstScoreSize    = 0;
Your Name's avatar
Your Name committed
425
    int classRoiNumSize = 0;
liucong's avatar
liucong committed
426
427
428
    dstRoiSize          = SSD_ALIGN16(ssdParameter.classNum * ssdParameter.topK * SSD_COORDI_NUM);
    dstScoreSize        = SSD_ALIGN16(ssdParameter.classNum * ssdParameter.topK);
    classRoiNumSize     = SSD_ALIGN16(ssdParameter.classNum);
Your Name's avatar
Your Name committed
429
430

    // 申请内存,并分配
liucong's avatar
liucong committed
431
432
433
434
435
436
437
438
    int totalSize = totalSizeOfClasReg + SSD_COORDI_NUM * 2 * ssdParameter.softMaxOutChn +
                    softMaxSize + detectionSize + dstRoiSize + classRoiNumSize + dstScoreSize;
    ssdParameter.buffer = new int[totalSize];
    int* data           = ssdParameter.buffer;
    memset(data, 0, totalSize * sizeof(int)); // 初始化0
    int offset = 0;
    for(int i = 0; i < ssdParameter.numberOfPriorBoxLayer; ++i)
    {
Your Name's avatar
Your Name committed
439

liucong's avatar
liucong committed
440
441
442
        int* dataOfClasReg             = data + offset;
        ssdParameter.classification[i] = dataOfClasReg;
        ssdParameter.regression[i]     = dataOfClasReg + ssdParameter.softMaxInChn[i];
Your Name's avatar
Your Name committed
443

liucong's avatar
liucong committed
444
445
446
447
448
449
450
451
452
        offset += (ssdParameter.softMaxInChn[i] + ssdParameter.detectInputChn[i]);
    }
    ssdParameter.priorboxOutputData = data + totalSizeOfClasReg;
    ssdParameter.softMaxOutputData =
        ssdParameter.priorboxOutputData + SSD_COORDI_NUM * 2 * ssdParameter.softMaxOutChn;
    ssdParameter.getResultBuffer = ssdParameter.softMaxOutputData + softMaxSize;
    ssdParameter.dstRoi          = ssdParameter.getResultBuffer + detectionSize;
    ssdParameter.classRoiNum     = ssdParameter.dstRoi + dstRoiSize;
    ssdParameter.dstScore        = ssdParameter.classRoiNum + classRoiNumSize;
Your Name's avatar
Your Name committed
453
454
}

liucong's avatar
liucong committed
455
456
457
void DetectorRetinaFace::GetResult(const vector<vector<float>>& classifications,
                                   const vector<vector<float>>& regressions,
                                   vector<ResultOfDetection>& resultsOfDetection)
Your Name's avatar
Your Name committed
458
{
liucong's avatar
liucong committed
459
    int numberOfPriorBoxLayer = ssdParameter.numberOfPriorBoxLayer;
Your Name's avatar
Your Name committed
460
461
462
463
464

    // 类型转换
    for(int i = 0; i < numberOfPriorBoxLayer; i++)
    {
        // 分类
liucong's avatar
liucong committed
465
466
        vector<float> classificationOfEachLayer = classifications[i];
        for(int j = 0; j < classificationOfEachLayer.size(); ++j)
Your Name's avatar
Your Name committed
467
        {
liucong's avatar
liucong committed
468
            (ssdParameter.classification[i])[j] = classificationOfEachLayer[j] * SSD_QUANT_BASE;
Your Name's avatar
Your Name committed
469
470
471
        }

        // 回归
liucong's avatar
liucong committed
472
473
        vector<float> regressionOfEachLayer = regressions[i];
        for(int j = 0; j < regressionOfEachLayer.size(); ++j)
Your Name's avatar
Your Name committed
474
        {
liucong's avatar
liucong committed
475
            (ssdParameter.regression[i])[j] = regressionOfEachLayer[j] * SSD_QUANT_BASE;
Your Name's avatar
Your Name committed
476
477
478
479
480
481
        }
    }

    int* priorboxOutputData[SSD_MAX_PRIORBOX_LAYER_NUM];
    int* softMaxInputData[SSD_MAX_PRIORBOX_LAYER_NUM];
    int* detectionLocData[SSD_MAX_PRIORBOX_LAYER_NUM];
liucong's avatar
liucong committed
482
    int* softMaxOutputData  = NULL;
Your Name's avatar
Your Name committed
483
    int* detectionOutTmpBuf = NULL;
liucong's avatar
liucong committed
484
    int softMaxWidth[SSD_MAX_PRIORBOX_LAYER_NUM];
Your Name's avatar
Your Name committed
485
    int size = 0;
liucong's avatar
liucong committed
486
    int i    = 0;
Your Name's avatar
Your Name committed
487

liucong's avatar
liucong committed
488
489
    /////////////////////////////////// PriorBoxLayer:生成所有priorbox
    //////////////////////////////////////
Your Name's avatar
Your Name committed
490
491
    // 分配priorboxOutputData内存空间
    priorboxOutputData[0] = ssdParameter.priorboxOutputData;
liucong's avatar
liucong committed
492
    for(i = 1; i < numberOfPriorBoxLayer; i++)
Your Name's avatar
Your Name committed
493
    {
liucong's avatar
liucong committed
494
        size = ssdParameter.softMaxInChn[i - 1] / ssdParameter.classNum * SSD_COORDI_NUM * 2;
Your Name's avatar
Your Name committed
495
496
        priorboxOutputData[i] = priorboxOutputData[i - 1] + size;
    }
liucong's avatar
liucong committed
497
    for(i = 0; i < numberOfPriorBoxLayer; i++)
Your Name's avatar
Your Name committed
498
    {
liucong's avatar
liucong committed
499
        PriorBoxLayer(i, priorboxOutputData[i]);
Your Name's avatar
Your Name committed
500
501
    }

liucong's avatar
liucong committed
502
503
    /////////////////////////////////// SoftmaxLayer:计算所有priorbox的置信度
    //////////////////////////////////////
Your Name's avatar
Your Name committed
504
    // 分配softMaxOutputData内存空间
liucong's avatar
liucong committed
505
    softMaxOutputData = ssdParameter.softMaxOutputData;
Your Name's avatar
Your Name committed
506
507
508
    for(i = 0; i < numberOfPriorBoxLayer; i++)
    {
        softMaxInputData[i] = ssdParameter.classification[i];
liucong's avatar
liucong committed
509
        softMaxWidth[i]     = ssdParameter.convChannel[i * 2 + 1];
Your Name's avatar
Your Name committed
510
    }
liucong's avatar
liucong committed
511
    SoftmaxLayer(softMaxWidth, softMaxInputData, softMaxOutputData);
Your Name's avatar
Your Name committed
512

liucong's avatar
liucong committed
513
514
515
    ///////////////////////////////////
    ///DetectionOutputLayer:对网络输出值解码并经过NMS得到最后的检测结果
    //////////////////////////////////////
Your Name's avatar
Your Name committed
516
517
518
519
520
521
    // 分配DetectionOut内存空间
    detectionOutTmpBuf = ssdParameter.getResultBuffer;
    for(i = 0; i < numberOfPriorBoxLayer; i++)
    {
        detectionLocData[i] = ssdParameter.regression[i];
    }
liucong's avatar
liucong committed
522
523
    DetectionOutputLayer(
        detectionLocData, priorboxOutputData, softMaxOutputData, detectionOutTmpBuf);
Your Name's avatar
Your Name committed
524
525
526
527
528

    // 获取最后的检测结果
    CreateDetectionResults(resultsOfDetection);
}

liucong's avatar
liucong committed
529
void DetectorRetinaFace::PriorBoxLayer(int indexOfLayer, int* priorboxOutputData)
Your Name's avatar
Your Name committed
530
531
{
    // 参数赋值
liucong's avatar
liucong committed
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
    int priorBoxWidth                 = ssdParameter.priorBoxWidth[indexOfLayer];
    int priorBoxHeight                = ssdParameter.priorBoxHeight[indexOfLayer];
    int srcImageWidth                 = ssdParameter.srcImageWidth;
    int srcImageHeight                = ssdParameter.srcImageHeight;
    vector<float> priorBoxMinSize     = ssdParameter.priorBoxMinSize[indexOfLayer];
    int minSizeNum                    = ssdParameter.minSizeNum[indexOfLayer];
    vector<float> priorBoxMaxSize     = ssdParameter.priorBoxMaxSize[indexOfLayer];
    int maxSizeNum                    = ssdParameter.maxSizeNum[indexOfLayer];
    int flip                          = ssdParameter.flip[indexOfLayer];
    int clip                          = ssdParameter.clip[indexOfLayer];
    int inputAspectRatioNum           = ssdParameter.inputAspectRatioNum[indexOfLayer];
    vector<float> priorBoxAspectRatio = ssdParameter.priorBoxAspectRatio[indexOfLayer];
    float priorBoxStepWidth           = ssdParameter.priorBoxStepWidth[indexOfLayer];
    float priorBoxStepHeight          = ssdParameter.priorBoxStepHeight[indexOfLayer];
    float offset                      = ssdParameter.offset;
    int* priorBoxVar                  = ssdParameter.priorBoxVar;

    int aspectRatioNum                      = 0;
    int index                               = 0;
    float aspectRatio[SSD_ASPECT_RATIO_NUM] = {0};
    int numPrior                            = 0;
    float centerX                           = 0;
    float centerY                           = 0;
    float boxHeight                         = 0;
    float boxWidth                          = 0;
    float maxBoxWidth                       = 0;
    int i                                   = 0;
    int j                                   = 0;
    int n                                   = 0;
    int h                                   = 0;
    int w                                   = 0;
Your Name's avatar
Your Name committed
563
564
565
566

    aspectRatioNum = 0;
    aspectRatio[0] = 1;
    aspectRatioNum++;
liucong's avatar
liucong committed
567
    for(i = 0; i < inputAspectRatioNum; i++)
Your Name's avatar
Your Name committed
568
569
    {
        aspectRatio[aspectRatioNum++] = priorBoxAspectRatio[i];
liucong's avatar
liucong committed
570
        if(flip)
Your Name's avatar
Your Name committed
571
572
573
574
575
576
577
        {
            aspectRatio[aspectRatioNum++] = 1.0f / priorBoxAspectRatio[i];
        }
    }
    numPrior = minSizeNum * aspectRatioNum + maxSizeNum;

    index = 0;
liucong's avatar
liucong committed
578
    for(h = 0; h < priorBoxHeight; h++)
Your Name's avatar
Your Name committed
579
    {
liucong's avatar
liucong committed
580
        for(w = 0; w < priorBoxWidth; w++)
Your Name's avatar
Your Name committed
581
582
583
        {
            centerX = (w + offset) * priorBoxStepWidth;
            centerY = (h + offset) * priorBoxStepHeight;
liucong's avatar
liucong committed
584
            for(n = 0; n < minSizeNum; n++)
Your Name's avatar
Your Name committed
585
586
            {
                // 首先产生宽高比为1的priorbox
liucong's avatar
liucong committed
587
588
                boxHeight                   = priorBoxMinSize[n];
                boxWidth                    = priorBoxMinSize[n];
Your Name's avatar
Your Name committed
589
590
591
592
593
594
                priorboxOutputData[index++] = (int)(centerX - boxWidth * SSD_HALF);
                priorboxOutputData[index++] = (int)(centerY - boxHeight * SSD_HALF);
                priorboxOutputData[index++] = (int)(centerX + boxWidth * SSD_HALF);
                priorboxOutputData[index++] = (int)(centerY + boxHeight * SSD_HALF);

                // 对于max_size,生成宽高比为1的priorbox,宽高为sqrt(min_size * max_size)
liucong's avatar
liucong committed
595
                if(maxSizeNum > 0)
Your Name's avatar
Your Name committed
596
                {
liucong's avatar
liucong committed
597
598
599
                    maxBoxWidth                 = sqrt(priorBoxMinSize[n] * priorBoxMaxSize[n]);
                    boxHeight                   = maxBoxWidth;
                    boxWidth                    = maxBoxWidth;
Your Name's avatar
Your Name committed
600
601
602
603
604
605
606
                    priorboxOutputData[index++] = (int)(centerX - boxWidth * SSD_HALF);
                    priorboxOutputData[index++] = (int)(centerY - boxHeight * SSD_HALF);
                    priorboxOutputData[index++] = (int)(centerX + boxWidth * SSD_HALF);
                    priorboxOutputData[index++] = (int)(centerY + boxHeight * SSD_HALF);
                }

                // 剩下的priorbox
liucong's avatar
liucong committed
607
                for(i = 1; i < aspectRatioNum; i++)
Your Name's avatar
Your Name committed
608
                {
liucong's avatar
liucong committed
609
610
                    boxWidth  = (float)(priorBoxMinSize[n] * sqrt(aspectRatio[i]));
                    boxHeight = (float)(priorBoxMinSize[n] / sqrt(aspectRatio[i]));
Your Name's avatar
Your Name committed
611
612
613
614
615
616
617
618
619
620

                    priorboxOutputData[index++] = (int)(centerX - boxWidth * SSD_HALF);
                    priorboxOutputData[index++] = (int)(centerY - boxHeight * SSD_HALF);
                    priorboxOutputData[index++] = (int)(centerX + boxWidth * SSD_HALF);
                    priorboxOutputData[index++] = (int)(centerY + boxHeight * SSD_HALF);
                }
            }
        }
    }

liucong's avatar
liucong committed
621
622
    // 越界处理 [0, srcImageWidth] & [0, srcImageHeight]
    if(clip)
Your Name's avatar
Your Name committed
623
    {
liucong's avatar
liucong committed
624
        for(i = 0; i < (int)(priorBoxWidth * priorBoxHeight * SSD_COORDI_NUM * numPrior / 2); i++)
Your Name's avatar
Your Name committed
625
        {
liucong's avatar
liucong committed
626
627
628
629
            priorboxOutputData[2 * i] =
                SSD_MIN((int)SSD_MAX(priorboxOutputData[2 * i], 0), srcImageWidth);
            priorboxOutputData[2 * i + 1] =
                SSD_MIN((int)SSD_MAX(priorboxOutputData[2 * i + 1], 0), srcImageHeight);
Your Name's avatar
Your Name committed
630
631
632
        }
    }
    // var
liucong's avatar
liucong committed
633
    for(h = 0; h < priorBoxHeight; h++)
Your Name's avatar
Your Name committed
634
    {
liucong's avatar
liucong committed
635
        for(w = 0; w < priorBoxWidth; w++)
Your Name's avatar
Your Name committed
636
        {
liucong's avatar
liucong committed
637
            for(i = 0; i < numPrior; i++)
Your Name's avatar
Your Name committed
638
            {
liucong's avatar
liucong committed
639
                for(j = 0; j < SSD_COORDI_NUM; j++)
Your Name's avatar
Your Name committed
640
641
642
643
644
645
646
647
                {
                    priorboxOutputData[index++] = (int)priorBoxVar[j];
                }
            }
        }
    }
}

liucong's avatar
liucong committed
648
649
650
void DetectorRetinaFace::SoftmaxLayer(int softMaxWidth[],
                                      int* softMaxInputData[],
                                      int* softMaxOutputData)
Your Name's avatar
Your Name committed
651
652
653
{

    // 参数赋值
liucong's avatar
liucong committed
654
655
656
657
658
659
660
661
662
    int softMaxInHeight = ssdParameter.softMaxInHeight;
    int* softMaxInChn   = ssdParameter.softMaxInChn;
    int concatNum       = ssdParameter.concatNum;
    int* convStride     = ssdParameter.convStride;

    int* inputData   = NULL;
    int* outputTmp   = NULL;
    int outerNum     = 0;
    int innerNum     = 0;
Your Name's avatar
Your Name committed
663
    int inputChannel = 0;
liucong's avatar
liucong committed
664
665
666
667
668
669
670
    int i            = 0;
    int concatCnt    = 0;
    int stride       = 0;
    int skip         = 0;
    int left         = 0;
    outputTmp        = softMaxOutputData;
    for(concatCnt = 0; concatCnt < concatNum; concatCnt++)
Your Name's avatar
Your Name committed
671
    {
liucong's avatar
liucong committed
672
673
        inputData    = softMaxInputData[concatCnt];
        stride       = convStride[concatCnt];
Your Name's avatar
Your Name committed
674
        inputChannel = softMaxInChn[concatCnt];
liucong's avatar
liucong committed
675
676
677
678
679
        outerNum     = inputChannel / softMaxInHeight;
        innerNum     = softMaxInHeight;
        skip         = softMaxWidth[concatCnt] / innerNum;
        left         = stride - softMaxWidth[concatCnt];
        for(i = 0; i < outerNum; i++)
Your Name's avatar
Your Name committed
680
        {
liucong's avatar
liucong committed
681
            ComputeSoftMax(inputData, (int)innerNum, outputTmp);
Your Name's avatar
Your Name committed
682
683
684
685
686
687
688
689
690
691
            inputData += innerNum;
            outputTmp += innerNum;
        }
    }
}

void DetectorRetinaFace::ComputeSoftMax(int* src, int size, int* dst)
{
    int max = 0;
    int sum = 0;
liucong's avatar
liucong committed
692
693
    int i   = 0;
    for(i = 0; i < size; ++i)
Your Name's avatar
Your Name committed
694
    {
liucong's avatar
liucong committed
695
        if(max < src[i])
Your Name's avatar
Your Name committed
696
697
698
699
        {
            max = src[i];
        }
    }
liucong's avatar
liucong committed
700
    for(i = 0; i < size; ++i)
Your Name's avatar
Your Name committed
701
    {
liucong's avatar
liucong committed
702
        dst[i] = (int)(SSD_QUANT_BASE * exp((float)(src[i] - max) / SSD_QUANT_BASE));
Your Name's avatar
Your Name committed
703
704
        sum += dst[i];
    }
liucong's avatar
liucong committed
705
    for(i = 0; i < size; ++i)
Your Name's avatar
Your Name committed
706
707
708
709
710
    {
        dst[i] = (int)(((float)dst[i] / (float)sum) * SSD_QUANT_BASE);
    }
}

liucong's avatar
liucong committed
711
712
713
714
void DetectorRetinaFace::DetectionOutputLayer(int* allLocPreds[],
                                              int* allPriorBoxes[],
                                              int* confScores,
                                              int* assistMemPool)
Your Name's avatar
Your Name committed
715
716
717
{

    // 参数赋值
liucong's avatar
liucong committed
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
    int concatNum       = ssdParameter.concatNum;
    int confThresh      = ssdParameter.confThresh;
    int classNum        = ssdParameter.classNum;
    int topK            = ssdParameter.topK;
    int keepTopK        = ssdParameter.keepTopK;
    int NMSThresh       = ssdParameter.NMSThresh;
    int* detectInputChn = ssdParameter.detectInputChn;
    int* dstScoreSrc    = ssdParameter.dstScore;
    int* dstBboxSrc     = ssdParameter.dstRoi;
    int* roiOutCntSrc   = ssdParameter.classRoiNum;

    int* locPreds          = NULL;
    int* priorBoxes        = NULL;
    int* priorVar          = NULL;
    int* allDecodeBoxes    = NULL;
    int* dstScore          = NULL;
    int* dstBbox           = NULL;
    int* classRoiNum       = NULL;
    int roiOutCnt          = 0;
    int* singleProposal    = NULL;
    int* afterTopK         = NULL;
    QuickSortStack* stack  = NULL;
    int priorNum           = 0;
    int numPredsPerClass   = 0;
    float priorWidth       = 0;
    float priorHeight      = 0;
    float priorCenterX     = 0;
    float priorCenterY     = 0;
Your Name's avatar
Your Name committed
746
747
    float decodeBoxCenterX = 0;
    float decodeBoxCenterY = 0;
liucong's avatar
liucong committed
748
749
750
751
752
753
754
755
756
757
758
    float decodeBoxWidth   = 0;
    float decodeBoxHeight  = 0;
    int srcIdx             = 0;
    int afterFilter        = 0;
    int afterTopK2         = 0;
    int keepCnt            = 0;
    int i                  = 0;
    int j                  = 0;
    int offset             = 0;
    priorNum               = 0;
    for(i = 0; i < concatNum; i++)
Your Name's avatar
Your Name committed
759
760
761
762
763
764
765
    {
        priorNum += detectInputChn[i] / SSD_COORDI_NUM;
    }

    // 缓存
    allDecodeBoxes = assistMemPool;
    singleProposal = allDecodeBoxes + priorNum * SSD_COORDI_NUM;
liucong's avatar
liucong committed
766
767
768
769
    afterTopK      = singleProposal + SSD_PROPOSAL_WIDTH * priorNum;
    stack          = (QuickSortStack*)(afterTopK + priorNum * SSD_PROPOSAL_WIDTH);
    srcIdx         = 0;
    for(i = 0; i < concatNum; i++)
Your Name's avatar
Your Name committed
770
771
    {
        // 回归预测值
liucong's avatar
liucong committed
772
        locPreds         = allLocPreds[i];
Your Name's avatar
Your Name committed
773
774
775
776
        numPredsPerClass = detectInputChn[i] / SSD_COORDI_NUM;

        // 获取priorbox
        priorBoxes = allPriorBoxes[i];
liucong's avatar
liucong committed
777
778
        priorVar   = priorBoxes + numPredsPerClass * SSD_COORDI_NUM;
        for(j = 0; j < numPredsPerClass; j++)
Your Name's avatar
Your Name committed
779
        {
liucong's avatar
liucong committed
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
            priorWidth =
                (float)(priorBoxes[j * SSD_COORDI_NUM + 2] - priorBoxes[j * SSD_COORDI_NUM]);
            priorHeight =
                (float)(priorBoxes[j * SSD_COORDI_NUM + 3] - priorBoxes[j * SSD_COORDI_NUM + 1]);
            priorCenterX =
                (priorBoxes[j * SSD_COORDI_NUM + 2] + priorBoxes[j * SSD_COORDI_NUM]) * SSD_HALF;
            priorCenterY =
                (priorBoxes[j * SSD_COORDI_NUM + 3] + priorBoxes[j * SSD_COORDI_NUM + 1]) *
                SSD_HALF;

            decodeBoxCenterX = ((float)priorVar[j * SSD_COORDI_NUM] / SSD_QUANT_BASE) *
                                   ((float)locPreds[j * SSD_COORDI_NUM] / SSD_QUANT_BASE) *
                                   priorWidth +
                               priorCenterX;

            decodeBoxCenterY = ((float)priorVar[j * SSD_COORDI_NUM + 1] / SSD_QUANT_BASE) *
                                   ((float)locPreds[j * SSD_COORDI_NUM + 1] / SSD_QUANT_BASE) *
                                   priorHeight +
                               priorCenterY;

            decodeBoxWidth = exp(((float)priorVar[j * SSD_COORDI_NUM + 2] / SSD_QUANT_BASE) *
                                 ((float)locPreds[j * SSD_COORDI_NUM + 2] / SSD_QUANT_BASE)) *
                             priorWidth;

            decodeBoxHeight = exp(((float)priorVar[j * SSD_COORDI_NUM + 3] / SSD_QUANT_BASE) *
                                  ((float)locPreds[j * SSD_COORDI_NUM + 3] / SSD_QUANT_BASE)) *
                              priorHeight;
Your Name's avatar
Your Name committed
807
808
809
810
811
812
813
814
815
816

            allDecodeBoxes[srcIdx++] = (int)(decodeBoxCenterX - decodeBoxWidth * SSD_HALF);
            allDecodeBoxes[srcIdx++] = (int)(decodeBoxCenterY - decodeBoxHeight * SSD_HALF);
            allDecodeBoxes[srcIdx++] = (int)(decodeBoxCenterX + decodeBoxWidth * SSD_HALF);
            allDecodeBoxes[srcIdx++] = (int)(decodeBoxCenterY + decodeBoxHeight * SSD_HALF);
        }
    }

    // 对每一类做NMS
    afterTopK2 = 0;
liucong's avatar
liucong committed
817
    for(i = 0; i < classNum; i++)
Your Name's avatar
Your Name committed
818
    {
liucong's avatar
liucong committed
819
        if(i == 0)
Your Name's avatar
Your Name committed
820
821
            continue;

liucong's avatar
liucong committed
822
        for(j = 0; j < priorNum; j++)
Your Name's avatar
Your Name committed
823
        {
liucong's avatar
liucong committed
824
            singleProposal[j * SSD_PROPOSAL_WIDTH]     = allDecodeBoxes[j * SSD_COORDI_NUM];
Your Name's avatar
Your Name committed
825
826
827
            singleProposal[j * SSD_PROPOSAL_WIDTH + 1] = allDecodeBoxes[j * SSD_COORDI_NUM + 1];
            singleProposal[j * SSD_PROPOSAL_WIDTH + 2] = allDecodeBoxes[j * SSD_COORDI_NUM + 2];
            singleProposal[j * SSD_PROPOSAL_WIDTH + 3] = allDecodeBoxes[j * SSD_COORDI_NUM + 3];
liucong's avatar
liucong committed
828
            singleProposal[j * SSD_PROPOSAL_WIDTH + 4] = confScores[j * classNum + i];
Your Name's avatar
Your Name committed
829
830
            singleProposal[j * SSD_PROPOSAL_WIDTH + 5] = 0;
        }
liucong's avatar
liucong committed
831
        QuickSort(singleProposal, 0, priorNum - 1, stack, topK);
Your Name's avatar
Your Name committed
832
833
        afterFilter = (priorNum < topK) ? priorNum : topK;
        NonMaxSuppression(singleProposal, afterFilter, NMSThresh, afterFilter);
liucong's avatar
liucong committed
834
835
836
        roiOutCnt   = 0;
        dstScore    = (int*)dstScoreSrc;
        dstBbox     = (int*)dstBboxSrc;
Your Name's avatar
Your Name committed
837
838
839
        classRoiNum = (int*)roiOutCntSrc;
        dstScore += (int)afterTopK2;
        dstBbox += (int)(afterTopK2 * SSD_COORDI_NUM);
liucong's avatar
liucong committed
840
        for(j = 0; j < topK; j++)
Your Name's avatar
Your Name committed
841
        {
liucong's avatar
liucong committed
842
843
            if(singleProposal[j * SSD_PROPOSAL_WIDTH + 5] == 0 &&
               singleProposal[j * SSD_PROPOSAL_WIDTH + 4] > (int)confThresh)
Your Name's avatar
Your Name committed
844
            {
liucong's avatar
liucong committed
845
                dstScore[roiOutCnt]                 = singleProposal[j * 6 + 4];
Your Name's avatar
Your Name committed
846
                dstBbox[roiOutCnt * SSD_COORDI_NUM] = singleProposal[j * SSD_PROPOSAL_WIDTH];
liucong's avatar
liucong committed
847
848
849
850
851
852
                dstBbox[roiOutCnt * SSD_COORDI_NUM + 1] =
                    singleProposal[j * SSD_PROPOSAL_WIDTH + 1];
                dstBbox[roiOutCnt * SSD_COORDI_NUM + 2] =
                    singleProposal[j * SSD_PROPOSAL_WIDTH + 2];
                dstBbox[roiOutCnt * SSD_COORDI_NUM + 3] =
                    singleProposal[j * SSD_PROPOSAL_WIDTH + 3];
Your Name's avatar
Your Name committed
853
854
855
856
857
858
859
860
                roiOutCnt++;
            }
        }
        classRoiNum[i] = (int)roiOutCnt;
        afterTopK2 += roiOutCnt;
    }

    keepCnt = 0;
liucong's avatar
liucong committed
861
862
    offset  = 0;
    if(afterTopK2 > keepTopK)
Your Name's avatar
Your Name committed
863
864
    {
        offset = classRoiNum[0];
liucong's avatar
liucong committed
865
        for(i = 1; i < classNum; i++)
Your Name's avatar
Your Name committed
866
        {
liucong's avatar
liucong committed
867
868
            dstScore    = (int*)dstScoreSrc;
            dstBbox     = (int*)dstBboxSrc;
Your Name's avatar
Your Name committed
869
870
871
            classRoiNum = (int*)roiOutCntSrc;
            dstScore += (int)(offset);
            dstBbox += (int)(offset * SSD_COORDI_NUM);
liucong's avatar
liucong committed
872
            for(j = 0; j < (int)classRoiNum[i]; j++)
Your Name's avatar
Your Name committed
873
            {
liucong's avatar
liucong committed
874
                afterTopK[keepCnt * SSD_PROPOSAL_WIDTH]     = dstBbox[j * SSD_COORDI_NUM];
Your Name's avatar
Your Name committed
875
876
877
878
879
880
881
882
883
                afterTopK[keepCnt * SSD_PROPOSAL_WIDTH + 1] = dstBbox[j * SSD_COORDI_NUM + 1];
                afterTopK[keepCnt * SSD_PROPOSAL_WIDTH + 2] = dstBbox[j * SSD_COORDI_NUM + 2];
                afterTopK[keepCnt * SSD_PROPOSAL_WIDTH + 3] = dstBbox[j * SSD_COORDI_NUM + 3];
                afterTopK[keepCnt * SSD_PROPOSAL_WIDTH + 4] = dstScore[j];
                afterTopK[keepCnt * SSD_PROPOSAL_WIDTH + 5] = i;
                keepCnt++;
            }
            offset = offset + classRoiNum[i];
        }
liucong's avatar
liucong committed
884
        QuickSort(afterTopK, 0, keepCnt - 1, stack, keepCnt);
Your Name's avatar
Your Name committed
885
886
887

        offset = 0;
        offset = classRoiNum[0];
liucong's avatar
liucong committed
888
        for(i = 1; i < classNum; i++)
Your Name's avatar
Your Name committed
889
        {
liucong's avatar
liucong committed
890
891
892
            roiOutCnt   = 0;
            dstScore    = (int*)dstScoreSrc;
            dstBbox     = (int*)dstBboxSrc;
Your Name's avatar
Your Name committed
893
894
895
            classRoiNum = (int*)roiOutCntSrc;
            dstScore += (int)(offset);
            dstBbox += (int)(offset * SSD_COORDI_NUM);
liucong's avatar
liucong committed
896
            for(j = 0; j < keepTopK; j++)
Your Name's avatar
Your Name committed
897
            {
liucong's avatar
liucong committed
898
                if(afterTopK[j * SSD_PROPOSAL_WIDTH + 5] == i)
Your Name's avatar
Your Name committed
899
                {
liucong's avatar
liucong committed
900
901
                    dstScore[roiOutCnt]                     = afterTopK[j * SSD_PROPOSAL_WIDTH + 4];
                    dstBbox[roiOutCnt * SSD_COORDI_NUM]     = afterTopK[j * SSD_PROPOSAL_WIDTH];
Your Name's avatar
Your Name committed
902
903
904
905
906
907
908
909
910
911
912
913
                    dstBbox[roiOutCnt * SSD_COORDI_NUM + 1] = afterTopK[j * SSD_PROPOSAL_WIDTH + 1];
                    dstBbox[roiOutCnt * SSD_COORDI_NUM + 2] = afterTopK[j * SSD_PROPOSAL_WIDTH + 2];
                    dstBbox[roiOutCnt * SSD_COORDI_NUM + 3] = afterTopK[j * SSD_PROPOSAL_WIDTH + 3];
                    roiOutCnt++;
                }
            }
            classRoiNum[i] = (int)roiOutCnt;
            offset += roiOutCnt;
        }
    }
}

liucong's avatar
liucong committed
914
915
vector<float>
DetectorRetinaFace::PermuteLayer(const vector<float>& data, int width, int height, int channels)
Your Name's avatar
Your Name committed
916
917
{
    vector<float> result(data.size());
liucong's avatar
liucong committed
918
919
920
    int index       = 0;
    int channelStep = width * height;
    for(int h = 0; h < height; h++)
Your Name's avatar
Your Name committed
921
    {
liucong's avatar
liucong committed
922
        for(int w = 0; w < width; w++)
Your Name's avatar
Your Name committed
923
        {
liucong's avatar
liucong committed
924
            for(int c = 0; c < channels; c++)
Your Name's avatar
Your Name committed
925
            {
liucong's avatar
liucong committed
926
                result[index++] = data[c * channelStep + h * width + w];
Your Name's avatar
Your Name committed
927
928
929
930
931
932
            }
        }
    }
    return result;
}

liucong's avatar
liucong committed
933
void DetectorRetinaFace::QuickSort(int* src, int low, int high, QuickSortStack* stack, int maxNum)
Your Name's avatar
Your Name committed
934
{
liucong's avatar
liucong committed
935
936
937
    int i             = low;
    int j             = high;
    int top           = 0;
Your Name's avatar
Your Name committed
938
    int keyConfidence = src[SSD_PROPOSAL_WIDTH * low + 4];
liucong's avatar
liucong committed
939
940
    stack[top].min    = low;
    stack[top].max    = high;
Your Name's avatar
Your Name committed
941
942
943

    while(top > -1)
    {
liucong's avatar
liucong committed
944
        low  = stack[top].min;
Your Name's avatar
Your Name committed
945
        high = stack[top].max;
liucong's avatar
liucong committed
946
947
        i    = low;
        j    = high;
Your Name's avatar
Your Name committed
948
949
950
951
952
953
954
955
956
957
958
959
        top--;

        keyConfidence = src[SSD_PROPOSAL_WIDTH * low + 4];

        while(i < j)
        {
            while((i < j) && (keyConfidence > src[j * SSD_PROPOSAL_WIDTH + 4]))
            {
                j--;
            }
            if(i < j)
            {
liucong's avatar
liucong committed
960
                Swap(&src[i * SSD_PROPOSAL_WIDTH], &src[j * SSD_PROPOSAL_WIDTH]);
Your Name's avatar
Your Name committed
961
962
963
                i++;
            }

liucong's avatar
liucong committed
964
            while((i < j) && (keyConfidence < src[i * SSD_PROPOSAL_WIDTH + 4]))
Your Name's avatar
Your Name committed
965
966
967
968
969
            {
                i++;
            }
            if(i < j)
            {
liucong's avatar
liucong committed
970
                Swap(&src[i * SSD_PROPOSAL_WIDTH], &src[j * SSD_PROPOSAL_WIDTH]);
Your Name's avatar
Your Name committed
971
972
973
974
975
976
                j--;
            }
        }

        if(low <= maxNum)
        {
liucong's avatar
liucong committed
977
978
979
980
981
982
            if(low < i - 1)
            {
                top++;
                stack[top].min = low;
                stack[top].max = i - 1;
            }
Your Name's avatar
Your Name committed
983

liucong's avatar
liucong committed
984
985
986
987
988
989
            if(high > i + 1)
            {
                top++;
                stack[top].min = i + 1;
                stack[top].max = high;
            }
Your Name's avatar
Your Name committed
990
991
992
993
        }
    }
}

liucong's avatar
liucong committed
994
995
996
997
void DetectorRetinaFace::NonMaxSuppression(int* proposals,
                                           int anchorsNum,
                                           int NMSThresh,
                                           int maxRoiNum)
Your Name's avatar
Your Name committed
998
{
liucong's avatar
liucong committed
999
1000
1001
1002
1003
1004
1005
1006
    int xMin1     = 0;
    int yMin1     = 0;
    int xMax1     = 0;
    int yMax1     = 0;
    int xMin2     = 0;
    int yMin2     = 0;
    int xMax2     = 0;
    int yMax2     = 0;
Your Name's avatar
Your Name committed
1007
1008
    int areaTotal = 0;
    int areaInter = 0;
liucong's avatar
liucong committed
1009
1010
1011
1012
1013
    int i         = 0;
    int j         = 0;
    int num       = 0;
    int NoOverlap = 1;
    for(i = 0; i < anchorsNum && num < maxRoiNum; i++)
Your Name's avatar
Your Name committed
1014
    {
liucong's avatar
liucong committed
1015
        if(proposals[SSD_PROPOSAL_WIDTH * i + 5] == 0)
Your Name's avatar
Your Name committed
1016
1017
        {
            num++;
liucong's avatar
liucong committed
1018
1019
1020
1021
1022
            xMin1 = proposals[SSD_PROPOSAL_WIDTH * i];
            yMin1 = proposals[SSD_PROPOSAL_WIDTH * i + 1];
            xMax1 = proposals[SSD_PROPOSAL_WIDTH * i + 2];
            yMax1 = proposals[SSD_PROPOSAL_WIDTH * i + 3];
            for(j = i + 1; j < anchorsNum; j++)
Your Name's avatar
Your Name committed
1023
            {
liucong's avatar
liucong committed
1024
                if(proposals[SSD_PROPOSAL_WIDTH * j + 5] == 0)
Your Name's avatar
Your Name committed
1025
                {
liucong's avatar
liucong committed
1026
1027
1028
1029
1030
1031
                    xMin2 = proposals[SSD_PROPOSAL_WIDTH * j];
                    yMin2 = proposals[SSD_PROPOSAL_WIDTH * j + 1];
                    xMax2 = proposals[SSD_PROPOSAL_WIDTH * j + 2];
                    yMax2 = proposals[SSD_PROPOSAL_WIDTH * j + 3];
                    NoOverlap =
                        (xMin2 > xMax1) || (xMax2 < xMin1) || (yMin2 > yMax1) || (yMax2 < yMin1);
Your Name's avatar
Your Name committed
1032
1033
1034
1035
                    if(NoOverlap)
                    {
                        continue;
                    }
liucong's avatar
liucong committed
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
                    ComputeOverlap(xMin1,
                                   yMin1,
                                   xMax1,
                                   yMax1,
                                   xMin2,
                                   yMin2,
                                   xMax2,
                                   yMax2,
                                   &areaTotal,
                                   &areaInter);
                    if(areaInter * SSD_QUANT_BASE > ((int)NMSThresh * areaTotal))
Your Name's avatar
Your Name committed
1047
                    {
liucong's avatar
liucong committed
1048
1049
                        if(proposals[SSD_PROPOSAL_WIDTH * i + 4] >=
                           proposals[SSD_PROPOSAL_WIDTH * j + 4])
Your Name's avatar
Your Name committed
1050
                        {
liucong's avatar
liucong committed
1051
                            proposals[SSD_PROPOSAL_WIDTH * j + 5] = 1;
Your Name's avatar
Your Name committed
1052
1053
1054
                        }
                        else
                        {
liucong's avatar
liucong committed
1055
                            proposals[SSD_PROPOSAL_WIDTH * i + 5] = 1;
Your Name's avatar
Your Name committed
1056
1057
1058
1059
1060
1061
1062
1063
                        }
                    }
                }
            }
        }
    }
}

liucong's avatar
liucong committed
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
void DetectorRetinaFace::ComputeOverlap(int xMin1,
                                        int yMin1,
                                        int xMax1,
                                        int yMax1,
                                        int xMin2,
                                        int yMin2,
                                        int xMax2,
                                        int yMax2,
                                        int* areaSum,
                                        int* areaInter)
Your Name's avatar
Your Name committed
1074
{
liucong's avatar
liucong committed
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084

    int inter       = 0;
    int s32Total    = 0;
    int xMin        = 0;
    int yMin        = 0;
    int xMax        = 0;
    int yMax        = 0;
    int area1       = 0;
    int area2       = 0;
    int interWidth  = 0;
Your Name's avatar
Your Name committed
1085
1086
1087
1088
1089
1090
1091
    int interHeight = 0;

    xMin = SSD_MAX(xMin1, xMin2);
    yMin = SSD_MAX(yMin1, yMin2);
    xMax = SSD_MIN(xMax1, xMax2);
    yMax = SSD_MIN(yMax1, yMax2);

liucong's avatar
liucong committed
1092
    interWidth  = xMax - xMin + 1;
Your Name's avatar
Your Name committed
1093
1094
    interHeight = yMax - yMin + 1;

liucong's avatar
liucong committed
1095
1096
    interWidth  = (interWidth >= 0) ? interWidth : 0;
    interHeight = (interHeight >= 0) ? interHeight : 0;
Your Name's avatar
Your Name committed
1097
1098
1099
1100
1101
1102
1103

    inter = interWidth * interHeight;
    area1 = (xMax1 - xMin1 + 1) * (yMax1 - yMin1 + 1);
    area2 = (xMax2 - xMin2 + 1) * (yMax2 - yMin2 + 1);

    s32Total = area1 + area2 - inter;

liucong's avatar
liucong committed
1104
    *areaSum   = s32Total;
Your Name's avatar
Your Name committed
1105
1106
1107
1108
1109
    *areaInter = inter;
}

void DetectorRetinaFace::Swap(int* src1, int* src2)
{
liucong's avatar
liucong committed
1110
    int i    = 0;
Your Name's avatar
Your Name committed
1111
    int temp = 0;
liucong's avatar
liucong committed
1112
    for(i = 0; i < SSD_PROPOSAL_WIDTH; i++)
Your Name's avatar
Your Name committed
1113
    {
liucong's avatar
liucong committed
1114
        temp    = src1[i];
Your Name's avatar
Your Name committed
1115
1116
1117
1118
1119
        src1[i] = src2[i];
        src2[i] = temp;
    }
}

liucong's avatar
liucong committed
1120
void DetectorRetinaFace::CreateDetectionResults(std::vector<ResultOfDetection>& resultsOfDetection)
Your Name's avatar
Your Name committed
1121
1122
{
    // 参数赋值
liucong's avatar
liucong committed
1123
1124
1125
1126
1127
    int* score              = ssdParameter.dstScore;
    int* roi                = ssdParameter.dstRoi;
    int* classRoiNum        = ssdParameter.classRoiNum;
    float printResultThresh = ((float)ssdParameter.confThresh) / SSD_QUANT_BASE;
    int classNum            = ssdParameter.classNum;
Your Name's avatar
Your Name committed
1128
1129
1130

    int i = 0, j = 0;
    int roiNumBias = 0;
liucong's avatar
liucong committed
1131
1132
1133
1134
    int scoreBias  = 0;
    int bboxBias   = 0;
    float score2   = 0.0f;
    int xMin = 0, yMin = 0, xMax = 0, yMax = 0;
Your Name's avatar
Your Name committed
1135
1136

    roiNumBias += classRoiNum[0];
liucong's avatar
liucong committed
1137
    for(i = 1; i < classNum; i++)
Your Name's avatar
Your Name committed
1138
1139
    {
        scoreBias = roiNumBias;
liucong's avatar
liucong committed
1140
        bboxBias  = roiNumBias * SSD_COORDI_NUM;
Your Name's avatar
Your Name committed
1141

liucong's avatar
liucong committed
1142
        if((float)score[scoreBias] / SSD_QUANT_BASE >= printResultThresh && classRoiNum[i] != 0)
Your Name's avatar
Your Name committed
1143
        {
liucong's avatar
liucong committed
1144
            // printf("==== The %d th class box info====\n", i);
Your Name's avatar
Your Name committed
1145
        }
liucong's avatar
liucong committed
1146
        for(j = 0; j < (int)classRoiNum[i]; j++)
Your Name's avatar
Your Name committed
1147
1148
        {
            score2 = (float)score[scoreBias + j] / SSD_QUANT_BASE;
liucong's avatar
liucong committed
1149
            if(score2 < printResultThresh)
Your Name's avatar
Your Name committed
1150
1151
1152
            {
                break;
            }
liucong's avatar
liucong committed
1153
1154
1155
1156
            xMin = roi[bboxBias + j * SSD_COORDI_NUM];
            yMin = roi[bboxBias + j * SSD_COORDI_NUM + 1];
            xMax = roi[bboxBias + j * SSD_COORDI_NUM + 2];
            yMax = roi[bboxBias + j * SSD_COORDI_NUM + 3];
Your Name's avatar
Your Name committed
1157
1158

            ResultOfDetection result;
liucong's avatar
liucong committed
1159
1160
1161
1162
1163
1164
            result.boundingBox.x      = xMin;
            result.boundingBox.y      = yMin;
            result.boundingBox.width  = xMax - xMin + 1;
            result.boundingBox.height = yMax - yMin + 1;
            result.classID            = i;
            result.confidence         = score2;
Your Name's avatar
Your Name committed
1165
1166
1167
1168
1169
1170
            resultsOfDetection.push_back(result);
        }
        roiNumBias += classRoiNum[i];
    }
}

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