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