15
#include "yolov3detectionoutput.h"
17
#include "layer_type.h"
23
Yolov3DetectionOutput::Yolov3DetectionOutput()
25
one_blob_only = false;
26
support_inplace = false;
37
Yolov3DetectionOutput::~Yolov3DetectionOutput()
42
int Yolov3DetectionOutput::load_param(const ParamDict& pd)
44
num_class = pd.get(0, 20);
45
num_box = pd.get(1, 5);
46
confidence_threshold = pd.get(2, 0.01f);
47
nms_threshold = pd.get(3, 0.45f);
48
biases = pd.get(4, Mat());
49
mask = pd.get(5, Mat());
50
anchors_scale = pd.get(6, Mat());
54
static inline float intersection_area(const Yolov3DetectionOutput::BBoxRect& a, const Yolov3DetectionOutput::BBoxRect& b)
56
if (a.xmin > b.xmax || a.xmax < b.xmin || a.ymin > b.ymax || a.ymax < b.ymin)
62
float inter_width = std::min(a.xmax, b.xmax) - std::max(a.xmin, b.xmin);
63
float inter_height = std::min(a.ymax, b.ymax) - std::max(a.ymin, b.ymin);
65
return inter_width * inter_height;
68
void Yolov3DetectionOutput::qsort_descent_inplace(std::vector<BBoxRect>& datas, int left, int right) const
72
float p = datas[(left + right) / 2].score;
76
while (datas[i].score > p)
79
while (datas[j].score < p)
85
std::swap(datas[i], datas[j]);
93
qsort_descent_inplace(datas, left, j);
96
qsort_descent_inplace(datas, i, right);
99
void Yolov3DetectionOutput::qsort_descent_inplace(std::vector<BBoxRect>& datas) const
104
qsort_descent_inplace(datas, 0, static_cast<int>(datas.size() - 1));
107
void Yolov3DetectionOutput::nms_sorted_bboxes(std::vector<BBoxRect>& bboxes, std::vector<size_t>& picked, float nms_threshold) const
111
const size_t n = bboxes.size();
113
for (size_t i = 0; i < n; i++)
115
const BBoxRect& a = bboxes[i];
118
for (int j = 0; j < (int)picked.size(); j++)
120
const BBoxRect& b = bboxes[picked[j]];
123
float inter_area = intersection_area(a, b);
124
float union_area = a.area + b.area - inter_area;
126
if (inter_area > nms_threshold * union_area)
138
static inline float sigmoid(float x)
140
return 1.f / (1.f + expf(-x));
143
int Yolov3DetectionOutput::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const
146
std::vector<BBoxRect> all_bbox_rects;
148
for (size_t b = 0; b < bottom_blobs.size(); b++)
150
std::vector<std::vector<BBoxRect> > all_box_bbox_rects;
151
all_box_bbox_rects.resize(num_box);
152
const Mat& bottom_top_blobs = bottom_blobs[b];
154
int w = bottom_top_blobs.w;
155
int h = bottom_top_blobs.h;
156
int channels = bottom_top_blobs.c;
158
const int channels_per_box = channels / num_box;
161
if (channels_per_box != 4 + 1 + num_class)
163
size_t mask_offset = b * num_box;
164
int net_w = (int)(anchors_scale[b] * w);
165
int net_h = (int)(anchors_scale[b] * h);
169
#pragma omp parallel for num_threads(opt.num_threads)
170
for (int pp = 0; pp < num_box; pp++)
172
int p = pp * channels_per_box;
173
int biases_index = static_cast<int>(mask[pp + mask_offset]);
175
const float bias_w = biases[biases_index * 2];
176
const float bias_h = biases[biases_index * 2 + 1];
178
const float* xptr = bottom_top_blobs.channel(p);
179
const float* yptr = bottom_top_blobs.channel(p + 1);
180
const float* wptr = bottom_top_blobs.channel(p + 2);
181
const float* hptr = bottom_top_blobs.channel(p + 3);
183
const float* box_score_ptr = bottom_top_blobs.channel(p + 4);
186
Mat scores = bottom_top_blobs.channel_range(p + 5, num_class);
189
for (int i = 0; i < h; i++)
191
for (int j = 0; j < w; j++)
195
float class_score = -FLT_MAX;
196
for (int q = 0; q < num_class; q++)
198
float score = scores.channel(q).row(i)[j];
199
if (score > class_score)
207
float confidence = 1.f / ((1.f + expf(-box_score_ptr[0]) * (1.f + expf(-class_score))));
208
if (confidence >= confidence_threshold)
211
float bbox_cx = (j + sigmoid(xptr[0])) / w;
212
float bbox_cy = (i + sigmoid(yptr[0])) / h;
213
float bbox_w = expf(wptr[0]) * bias_w / net_w;
214
float bbox_h = expf(hptr[0]) * bias_h / net_h;
216
float bbox_xmin = bbox_cx - bbox_w * 0.5f;
217
float bbox_ymin = bbox_cy - bbox_h * 0.5f;
218
float bbox_xmax = bbox_cx + bbox_w * 0.5f;
219
float bbox_ymax = bbox_cy + bbox_h * 0.5f;
221
float area = bbox_w * bbox_h;
223
BBoxRect c = {confidence, bbox_xmin, bbox_ymin, bbox_xmax, bbox_ymax, area, class_index};
224
all_box_bbox_rects[pp].push_back(c);
237
for (int i = 0; i < num_box; i++)
239
const std::vector<BBoxRect>& box_bbox_rects = all_box_bbox_rects[i];
241
all_bbox_rects.insert(all_bbox_rects.end(), box_bbox_rects.begin(), box_bbox_rects.end());
246
qsort_descent_inplace(all_bbox_rects);
249
std::vector<size_t> picked;
250
nms_sorted_bboxes(all_bbox_rects, picked, nms_threshold);
253
std::vector<BBoxRect> bbox_rects;
255
for (size_t i = 0; i < picked.size(); i++)
257
size_t z = picked[i];
258
bbox_rects.push_back(all_bbox_rects[z]);
262
int num_detected = static_cast<int>(bbox_rects.size());
263
if (num_detected == 0)
266
Mat& top_blob = top_blobs[0];
267
top_blob.create(6, num_detected, 4u, opt.blob_allocator);
268
if (top_blob.empty())
271
for (int i = 0; i < num_detected; i++)
273
const BBoxRect& r = bbox_rects[i];
274
float score = r.score;
275
float* outptr = top_blob.row(i);
277
outptr[0] = r.label + 1.0f;