1 // Tencent is pleased to support the open source community by making ncnn available.
2 //
3 // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
4 //
5 // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // https://opensource.org/licenses/BSD-3-Clause
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14
15 #include "priorbox.h"
16
17 #include <math.h>
18
19 namespace ncnn {
20
PriorBox()21 PriorBox::PriorBox()
22 {
23 one_blob_only = false;
24 support_inplace = false;
25 }
26
load_param(const ParamDict & pd)27 int PriorBox::load_param(const ParamDict& pd)
28 {
29 min_sizes = pd.get(0, Mat());
30 max_sizes = pd.get(1, Mat());
31 aspect_ratios = pd.get(2, Mat());
32 variances[0] = pd.get(3, 0.1f);
33 variances[1] = pd.get(4, 0.1f);
34 variances[2] = pd.get(5, 0.2f);
35 variances[3] = pd.get(6, 0.2f);
36 flip = pd.get(7, 1);
37 clip = pd.get(8, 0);
38 image_width = pd.get(9, 0);
39 image_height = pd.get(10, 0);
40 step_width = pd.get(11, -233.f);
41 step_height = pd.get(12, -233.f);
42 offset = pd.get(13, 0.f);
43 step_mmdetection = pd.get(14, 0);
44 center_mmdetection = pd.get(15, 0);
45
46 return 0;
47 }
48
forward(const std::vector<Mat> & bottom_blobs,std::vector<Mat> & top_blobs,const Option & opt) const49 int PriorBox::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const
50 {
51 int w = bottom_blobs[0].w;
52 int h = bottom_blobs[0].h;
53
54 if (bottom_blobs.size() == 1 && image_width == -233 && image_height == -233 && max_sizes.empty())
55 {
56 // mxnet style _contrib_MultiBoxPrior
57 float step_w = step_width;
58 float step_h = step_height;
59 if (step_w == -233)
60 step_w = 1.f / (float)w;
61 if (step_h == -233)
62 step_h = 1.f / (float)h;
63
64 int num_sizes = min_sizes.w;
65 int num_ratios = aspect_ratios.w;
66
67 int num_prior = num_sizes - 1 + num_ratios;
68
69 Mat& top_blob = top_blobs[0];
70 top_blob.create(4 * w * h * num_prior, 4u, opt.blob_allocator);
71 if (top_blob.empty())
72 return -100;
73
74 #pragma omp parallel for num_threads(opt.num_threads)
75 for (int i = 0; i < h; i++)
76 {
77 float* box = (float*)top_blob + i * w * num_prior * 4;
78
79 float center_x = offset * step_w;
80 float center_y = offset * step_h + i * step_h;
81
82 for (int j = 0; j < w; j++)
83 {
84 // ratio = 1, various sizes
85 for (int k = 0; k < num_sizes; k++)
86 {
87 float size = min_sizes[k];
88 float cw = size * h / w / 2;
89 float ch = size / 2;
90
91 box[0] = center_x - cw;
92 box[1] = center_y - ch;
93 box[2] = center_x + cw;
94 box[3] = center_y + ch;
95 box += 4;
96 }
97
98 // various ratios, size = min_size = size[0]
99 float size = min_sizes[0];
100 for (int p = 1; p < num_ratios; p++)
101 {
102 float ratio = static_cast<float>(sqrt(aspect_ratios[p]));
103 float cw = size * h / w * ratio / 2;
104 float ch = size / ratio / 2;
105
106 box[0] = center_x - cw;
107 box[1] = center_y - ch;
108 box[2] = center_x + cw;
109 box[3] = center_y + ch;
110 box += 4;
111 }
112
113 center_x += step_w;
114 }
115 }
116
117 if (clip)
118 {
119 float* box = top_blob;
120 for (int i = 0; i < top_blob.w; i++)
121 {
122 box[i] = std::min(std::max(box[i], 0.f), 1.f);
123 }
124 }
125
126 return 0;
127 }
128
129 int image_w = image_width;
130 int image_h = image_height;
131 if (image_w == -233)
132 image_w = bottom_blobs[1].w;
133 if (image_h == -233)
134 image_h = bottom_blobs[1].h;
135
136 float step_w = step_width;
137 float step_h = step_height;
138 if (step_w == -233)
139 {
140 step_w = (float)image_w / w;
141 if (step_mmdetection)
142 step_w = static_cast<float>(ceil((float)image_w / w));
143 }
144 if (step_h == -233)
145 {
146 step_h = (float)image_h / h;
147 if (step_mmdetection)
148 step_h = static_cast<float>(ceil((float)image_h / h));
149 }
150
151 int num_min_size = min_sizes.w;
152 int num_max_size = max_sizes.w;
153 int num_aspect_ratio = aspect_ratios.w;
154
155 int num_prior = num_min_size * num_aspect_ratio + num_min_size + num_max_size;
156 if (flip)
157 num_prior += num_min_size * num_aspect_ratio;
158
159 Mat& top_blob = top_blobs[0];
160 top_blob.create(4 * w * h * num_prior, 2, 4u, opt.blob_allocator);
161 if (top_blob.empty())
162 return -100;
163
164 #pragma omp parallel for num_threads(opt.num_threads)
165 for (int i = 0; i < h; i++)
166 {
167 float* box = (float*)top_blob + i * w * num_prior * 4;
168
169 float center_x = offset * step_w;
170 float center_y = offset * step_h + i * step_h;
171 if (center_mmdetection)
172 {
173 center_x = offset * (step_w - 1);
174 center_y = offset * (step_h - 1) + i * step_h;
175 }
176
177 for (int j = 0; j < w; j++)
178 {
179 float box_w;
180 float box_h;
181
182 for (int k = 0; k < num_min_size; k++)
183 {
184 float min_size = min_sizes[k];
185
186 // min size box
187 box_w = box_h = min_size;
188
189 box[0] = (center_x - box_w * 0.5f) / image_w;
190 box[1] = (center_y - box_h * 0.5f) / image_h;
191 box[2] = (center_x + box_w * 0.5f) / image_w;
192 box[3] = (center_y + box_h * 0.5f) / image_h;
193
194 box += 4;
195
196 if (num_max_size > 0)
197 {
198 float max_size = max_sizes[k];
199
200 // max size box
201 box_w = box_h = static_cast<float>(sqrt(min_size * max_size));
202
203 box[0] = (center_x - box_w * 0.5f) / image_w;
204 box[1] = (center_y - box_h * 0.5f) / image_h;
205 box[2] = (center_x + box_w * 0.5f) / image_w;
206 box[3] = (center_y + box_h * 0.5f) / image_h;
207
208 box += 4;
209 }
210
211 // all aspect_ratios
212 for (int p = 0; p < num_aspect_ratio; p++)
213 {
214 float ar = aspect_ratios[p];
215
216 box_w = static_cast<float>(min_size * sqrt(ar));
217 box_h = static_cast<float>(min_size / sqrt(ar));
218
219 box[0] = (center_x - box_w * 0.5f) / image_w;
220 box[1] = (center_y - box_h * 0.5f) / image_h;
221 box[2] = (center_x + box_w * 0.5f) / image_w;
222 box[3] = (center_y + box_h * 0.5f) / image_h;
223
224 box += 4;
225
226 if (flip)
227 {
228 box[0] = (center_x - box_h * 0.5f) / image_w;
229 box[1] = (center_y - box_w * 0.5f) / image_h;
230 box[2] = (center_x + box_h * 0.5f) / image_w;
231 box[3] = (center_y + box_w * 0.5f) / image_h;
232
233 box += 4;
234 }
235 }
236 }
237
238 center_x += step_w;
239 }
240 }
241
242 if (clip)
243 {
244 float* box = top_blob;
245 for (int i = 0; i < top_blob.w; i++)
246 {
247 box[i] = std::min(std::max(box[i], 0.f), 1.f);
248 }
249 }
250
251 // set variance
252 float* var = top_blob.row(1);
253 for (int i = 0; i < top_blob.w / 4; i++)
254 {
255 var[0] = variances[0];
256 var[1] = variances[1];
257 var[2] = variances[2];
258 var[3] = variances[3];
259
260 var += 4;
261 }
262
263 return 0;
264 }
265
266 } // namespace ncnn
267