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 "crop.h"
16
17 namespace ncnn {
18
Crop()19 Crop::Crop()
20 {
21 one_blob_only = true;
22 support_inplace = false;
23 }
24
load_param(const ParamDict & pd)25 int Crop::load_param(const ParamDict& pd)
26 {
27 woffset = pd.get(0, 0);
28 hoffset = pd.get(1, 0);
29 doffset = pd.get(13, 0);
30 coffset = pd.get(2, 0);
31 outw = pd.get(3, 0);
32 outh = pd.get(4, 0);
33 outd = pd.get(14, 0);
34 outc = pd.get(5, 0);
35 woffset2 = pd.get(6, 0);
36 hoffset2 = pd.get(7, 0);
37 doffset2 = pd.get(15, 0);
38 coffset2 = pd.get(8, 0);
39
40 starts = pd.get(9, Mat());
41 ends = pd.get(10, Mat());
42 axes = pd.get(11, Mat());
43
44 bool numpy_style_slice = !starts.empty() && !ends.empty();
45
46 if (outw == 0 && outh == 0 && outd == 0 && outc == 0 && woffset2 == 0 && hoffset2 == 0 && doffset2 == 0 && coffset2 == 0 && !numpy_style_slice)
47 {
48 one_blob_only = false;
49 }
50
51 return 0;
52 }
53
54 template<typename T>
copy_cut_border_image(const Mat & src,Mat & dst,int top,int left)55 static void copy_cut_border_image(const Mat& src, Mat& dst, int top, int left)
56 {
57 int w = dst.w;
58 int h = dst.h;
59
60 const T* ptr = src.row<T>(top) + left;
61 T* outptr = dst; //.data;
62
63 for (int y = 0; y < h; y++)
64 {
65 if (w < 12)
66 {
67 for (int x = 0; x < w; x++)
68 {
69 outptr[x] = ptr[x];
70 }
71 }
72 else
73 {
74 memcpy(outptr, ptr, w * sizeof(T));
75 }
76 outptr += w;
77 ptr += src.w;
78 }
79 }
80
forward(const Mat & bottom_blob,Mat & top_blob,const Option & opt) const81 int Crop::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
82 {
83 int w = bottom_blob.w;
84 int h = bottom_blob.h;
85 int d = bottom_blob.d;
86 int channels = bottom_blob.c;
87 int dims = bottom_blob.dims;
88 size_t elemsize = bottom_blob.elemsize;
89
90 int _woffset, _hoffset, _doffset, _coffset;
91 int _outw = -1, _outh = -1, _outd = -1, _outc;
92 resolve_crop_roi(bottom_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc);
93
94 if (dims == 1)
95 {
96 if (_outw == w)
97 {
98 top_blob = bottom_blob;
99 return 0;
100 }
101
102 top_blob.create(_outw, elemsize, opt.blob_allocator);
103 if (top_blob.empty())
104 return -100;
105
106 if (elemsize == 1)
107 copy_cut_border_image<signed char>(bottom_blob, top_blob, 0, _woffset);
108 if (elemsize == 2)
109 copy_cut_border_image<unsigned short>(bottom_blob, top_blob, 0, _woffset);
110 if (elemsize == 4)
111 copy_cut_border_image<float>(bottom_blob, top_blob, 0, _woffset);
112
113 return 0;
114 }
115
116 if (dims == 2)
117 {
118 if (_outw == w && _outh == h)
119 {
120 top_blob = bottom_blob;
121 return 0;
122 }
123
124 top_blob.create(_outw, _outh, elemsize, opt.blob_allocator);
125 if (top_blob.empty())
126 return -100;
127
128 if (elemsize == 1)
129 copy_cut_border_image<signed char>(bottom_blob, top_blob, _hoffset, _woffset);
130 if (elemsize == 2)
131 copy_cut_border_image<unsigned short>(bottom_blob, top_blob, _hoffset, _woffset);
132 if (elemsize == 4)
133 copy_cut_border_image<float>(bottom_blob, top_blob, _hoffset, _woffset);
134
135 return 0;
136 }
137
138 if (dims == 3)
139 {
140 if (_outw == w && _outh == h && _outc == channels)
141 {
142 top_blob = bottom_blob;
143 return 0;
144 }
145
146 const Mat bottom_blob_sliced = bottom_blob.channel_range(_coffset, _outc);
147
148 if (_outw == w && _outh == h)
149 {
150 top_blob = bottom_blob_sliced.clone();
151 if (top_blob.empty())
152 return -100;
153
154 return 0;
155 }
156
157 top_blob.create(_outw, _outh, _outc, elemsize, opt.blob_allocator);
158 if (top_blob.empty())
159 return -100;
160
161 #pragma omp parallel for num_threads(opt.num_threads)
162 for (int q = 0; q < _outc; q++)
163 {
164 const Mat m = bottom_blob_sliced.channel(q);
165 Mat borderm = top_blob.channel(q);
166
167 if (elemsize == 1)
168 copy_cut_border_image<signed char>(m, borderm, _hoffset, _woffset);
169 if (elemsize == 2)
170 copy_cut_border_image<unsigned short>(m, borderm, _hoffset, _woffset);
171 if (elemsize == 4)
172 copy_cut_border_image<float>(m, borderm, _hoffset, _woffset);
173 }
174
175 return 0;
176 }
177
178 if (dims == 4)
179 {
180 if (_outw == w && _outh == h && _outd == d && _outc == channels)
181 {
182 top_blob = bottom_blob;
183 return 0;
184 }
185
186 const Mat bottom_blob_sliced = bottom_blob.channel_range(_coffset, _outc);
187
188 if (_outw == w && _outh == h && _outd == d)
189 {
190 top_blob = bottom_blob_sliced.clone();
191 if (top_blob.empty())
192 return -100;
193
194 return 0;
195 }
196
197 top_blob.create(_outw, _outh, _outd, _outc, elemsize, opt.blob_allocator);
198 if (top_blob.empty())
199 return -100;
200
201 #pragma omp parallel for num_threads(opt.num_threads)
202 for (int q = 0; q < _outc; q++)
203 {
204 for (int z = 0; z < _outd; z++)
205 {
206 const Mat m = bottom_blob_sliced.channel(q).depth(z + _doffset);
207 Mat borderm = top_blob.channel(q).depth(z);
208
209 if (elemsize == 1)
210 copy_cut_border_image<signed char>(m, borderm, _hoffset, _woffset);
211 if (elemsize == 2)
212 copy_cut_border_image<unsigned short>(m, borderm, _hoffset, _woffset);
213 if (elemsize == 4)
214 copy_cut_border_image<float>(m, borderm, _hoffset, _woffset);
215 }
216 }
217
218 return 0;
219 }
220
221 return 0;
222 }
223
forward(const std::vector<Mat> & bottom_blobs,std::vector<Mat> & top_blobs,const Option & opt) const224 int Crop::forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const
225 {
226 const Mat& bottom_blob = bottom_blobs[0];
227 const Mat& reference_blob = bottom_blobs[1];
228
229 int w = bottom_blob.w;
230 int h = bottom_blob.h;
231 int d = bottom_blob.d;
232 int channels = bottom_blob.c;
233 int dims = bottom_blob.dims;
234 size_t elemsize = bottom_blob.elemsize;
235
236 Mat& top_blob = top_blobs[0];
237
238 int _woffset, _hoffset, _doffset, _coffset = -1;
239 int _outw = -1, _outh = -1, _outd = -1, _outc;
240 if (woffset == -233)
241 {
242 resolve_crop_roi(bottom_blob.shape(), (const int*)reference_blob, _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc);
243 }
244 else
245 {
246 resolve_crop_roi(bottom_blob.shape(), reference_blob.shape(), _woffset, _hoffset, _doffset, _coffset, _outw, _outh, _outd, _outc);
247 }
248
249 if (dims == 1)
250 {
251 if (_outw == w)
252 {
253 top_blob = bottom_blob;
254 return 0;
255 }
256
257 top_blob.create(_outw, elemsize, opt.blob_allocator);
258 if (top_blob.empty())
259 return -100;
260
261 if (elemsize == 1)
262 copy_cut_border_image<signed char>(bottom_blob, top_blob, 0, _woffset);
263 if (elemsize == 2)
264 copy_cut_border_image<unsigned short>(bottom_blob, top_blob, 0, _woffset);
265 if (elemsize == 4)
266 copy_cut_border_image<float>(bottom_blob, top_blob, 0, _woffset);
267
268 return 0;
269 }
270
271 if (dims == 2)
272 {
273 if (_outw == w && _outh == h)
274 {
275 top_blob = bottom_blob;
276 return 0;
277 }
278
279 top_blob.create(_outw, _outh, elemsize, opt.blob_allocator);
280 if (top_blob.empty())
281 return -100;
282
283 if (elemsize == 1)
284 copy_cut_border_image<signed char>(bottom_blob, top_blob, _hoffset, _woffset);
285 if (elemsize == 2)
286 copy_cut_border_image<unsigned short>(bottom_blob, top_blob, _hoffset, _woffset);
287 if (elemsize == 4)
288 copy_cut_border_image<float>(bottom_blob, top_blob, _hoffset, _woffset);
289
290 return 0;
291 }
292
293 if (dims == 3)
294 {
295 if (_outw == w && _outh == h && _outc == channels)
296 {
297 top_blob = bottom_blob;
298 return 0;
299 }
300
301 const Mat bottom_blob_sliced = bottom_blob.channel_range(_coffset, _outc);
302
303 if (_outw == w && _outh == h)
304 {
305 top_blob = bottom_blob_sliced.clone();
306 if (top_blob.empty())
307 return -100;
308
309 return 0;
310 }
311
312 top_blob.create(_outw, _outh, _outc, elemsize, opt.blob_allocator);
313 if (top_blob.empty())
314 return -100;
315
316 #pragma omp parallel for num_threads(opt.num_threads)
317 for (int q = 0; q < _outc; q++)
318 {
319 const Mat m = bottom_blob_sliced.channel(q);
320 Mat borderm = top_blob.channel(q);
321
322 if (elemsize == 1)
323 copy_cut_border_image<signed char>(m, borderm, _hoffset, _woffset);
324 if (elemsize == 2)
325 copy_cut_border_image<unsigned short>(m, borderm, _hoffset, _woffset);
326 if (elemsize == 4)
327 copy_cut_border_image<float>(m, borderm, _hoffset, _woffset);
328 }
329
330 return 0;
331 }
332
333 if (dims == 4)
334 {
335 if (_outw == w && _outh == h && _outd == d && _outc == channels)
336 {
337 top_blob = bottom_blob;
338 return 0;
339 }
340
341 const Mat bottom_blob_sliced = bottom_blob.channel_range(_coffset, _outc);
342
343 if (_outw == w && _outh == h && _outd == d)
344 {
345 top_blob = bottom_blob_sliced.clone();
346 if (top_blob.empty())
347 return -100;
348
349 return 0;
350 }
351
352 top_blob.create(_outw, _outh, _outd, _outc, elemsize, opt.blob_allocator);
353 if (top_blob.empty())
354 return -100;
355
356 #pragma omp parallel for num_threads(opt.num_threads)
357 for (int q = 0; q < _outc; q++)
358 {
359 for (int z = 0; z < _outd; z++)
360 {
361 const Mat m = bottom_blob_sliced.channel(q).depth(z + _doffset);
362 Mat borderm = top_blob.channel(q).depth(z);
363
364 if (elemsize == 1)
365 copy_cut_border_image<signed char>(m, borderm, _hoffset, _woffset);
366 if (elemsize == 2)
367 copy_cut_border_image<unsigned short>(m, borderm, _hoffset, _woffset);
368 if (elemsize == 4)
369 copy_cut_border_image<float>(m, borderm, _hoffset, _woffset);
370 }
371 }
372
373 return 0;
374 }
375
376 return 0;
377 }
378
resolve_crop_roi(const Mat & bottom_blob,int & _woffset,int & _hoffset,int & _doffset,int & _coffset,int & _outw,int & _outh,int & _outd,int & _outc) const379 void Crop::resolve_crop_roi(const Mat& bottom_blob, int& _woffset, int& _hoffset, int& _doffset, int& _coffset, int& _outw, int& _outh, int& _outd, int& _outc) const
380 {
381 int w = bottom_blob.w;
382 int h = bottom_blob.h;
383 int d = bottom_blob.d;
384 int channels = bottom_blob.c;
385 int dims = bottom_blob.dims;
386
387 bool numpy_style_slice = !starts.empty() && !ends.empty();
388 if (numpy_style_slice)
389 {
390 _woffset = 0;
391 _hoffset = 0;
392 _doffset = 0;
393 _coffset = 0;
394 _outw = w;
395 _outh = h;
396 _outd = d;
397 _outc = channels;
398
399 const int* starts_ptr = starts;
400 const int* ends_ptr = ends;
401 const int* axes_ptr = axes;
402
403 int _axes[4] = {0, 1, 2, 3};
404 int num_axis = axes.w;
405 if (num_axis == 0)
406 {
407 num_axis = dims;
408 }
409 else
410 {
411 for (int i = 0; i < num_axis; i++)
412 {
413 int axis = axes_ptr[i];
414 if (axis < 0)
415 axis = dims + axis;
416 _axes[i] = axis;
417 }
418 }
419
420 for (int i = 0; i < num_axis; i++)
421 {
422 int axis = _axes[i];
423 int start = starts_ptr[i];
424 int end = ends_ptr[i];
425
426 if (dims == 1) // axis == 0
427 {
428 if (start == -233) start = 0;
429 if (end == -233) end = w;
430 _woffset = start >= 0 ? start : w + start;
431 _outw = std::min(w, end > 0 ? end : w + end) - _woffset;
432 }
433 if (dims == 2)
434 {
435 if (axis == 0)
436 {
437 if (start == -233) start = 0;
438 if (end == -233) end = h;
439 _hoffset = start >= 0 ? start : h + start;
440 _outh = std::min(h, end > 0 ? end : h + end) - _hoffset;
441 }
442 if (axis == 1)
443 {
444 if (start == -233) start = 0;
445 if (end == -233) end = w;
446 _woffset = start >= 0 ? start : w + start;
447 _outw = std::min(w, end > 0 ? end : w + end) - _woffset;
448 }
449 }
450 if (dims == 3)
451 {
452 if (axis == 0)
453 {
454 if (start == -233) start = 0;
455 if (end == -233) end = channels;
456 _coffset = start >= 0 ? start : channels + start;
457 _outc = std::min(channels, end > 0 ? end : channels + end) - _coffset;
458 }
459 if (axis == 1)
460 {
461 if (start == -233) start = 0;
462 if (end == -233) end = h;
463 _hoffset = start >= 0 ? start : h + start;
464 _outh = std::min(h, end > 0 ? end : h + end) - _hoffset;
465 }
466 if (axis == 2)
467 {
468 if (start == -233) start = 0;
469 if (end == -233) end = w;
470 _woffset = start >= 0 ? start : w + start;
471 _outw = std::min(w, end > 0 ? end : w + end) - _woffset;
472 }
473 }
474 if (dims == 4)
475 {
476 if (axis == 0)
477 {
478 if (start == -233) start = 0;
479 if (end == -233) end = channels;
480 _coffset = start >= 0 ? start : channels + start;
481 _outc = std::min(channels, end > 0 ? end : channels + end) - _coffset;
482 }
483 if (axis == 1)
484 {
485 if (start == -233) start = 0;
486 if (end == -233) end = d;
487 _doffset = start >= 0 ? start : d + start;
488 _outd = std::min(d, end > 0 ? end : d + end) - _doffset;
489 }
490 if (axis == 2)
491 {
492 if (start == -233) start = 0;
493 if (end == -233) end = h;
494 _hoffset = start >= 0 ? start : h + start;
495 _outh = std::min(h, end > 0 ? end : h + end) - _hoffset;
496 }
497 if (axis == 3)
498 {
499 if (start == -233) start = 0;
500 if (end == -233) end = w;
501 _woffset = start >= 0 ? start : w + start;
502 _outw = std::min(w, end > 0 ? end : w + end) - _woffset;
503 }
504 }
505 }
506 }
507 else
508 {
509 _woffset = woffset;
510 _hoffset = hoffset;
511 _doffset = doffset;
512 _coffset = coffset;
513 _outw = w;
514 _outh = h;
515 _outd = d;
516 _outc = channels;
517
518 if (dims == 1)
519 {
520 _outw = w - woffset - woffset2;
521 if (outw != -233)
522 _outw = std::min(outw, _outw);
523 }
524 if (dims == 2)
525 {
526 _outw = w - woffset - woffset2;
527 if (outw != -233)
528 _outw = std::min(outw, _outw);
529
530 _outh = h - hoffset - hoffset2;
531 if (outh != -233)
532 _outh = std::min(outh, _outh);
533 }
534 if (dims == 3)
535 {
536 _outw = w - woffset - woffset2;
537 if (outw != -233)
538 _outw = std::min(outw, _outw);
539
540 _outh = h - hoffset - hoffset2;
541 if (outh != -233)
542 _outh = std::min(outh, _outh);
543
544 _outc = channels - coffset - coffset2;
545 if (outc != -233)
546 _outc = std::min(outc, _outc);
547 }
548 if (dims == 4)
549 {
550 _outw = w - woffset - woffset2;
551 if (outw != -233)
552 _outw = std::min(outw, _outw);
553
554 _outh = h - hoffset - hoffset2;
555 if (outh != -233)
556 _outh = std::min(outh, _outh);
557
558 _outd = d - doffset - doffset2;
559 if (outd != -233)
560 _outd = std::min(outd, _outd);
561
562 _outc = channels - coffset - coffset2;
563 if (outc != -233)
564 _outc = std::min(outc, _outc);
565 }
566 }
567 }
568
resolve_crop_roi(const Mat & bottom_blob,const Mat & reference_blob,int & _woffset,int & _hoffset,int & _doffset,int & _coffset,int & _outw,int & _outh,int & _outd,int & _outc) const569 void Crop::resolve_crop_roi(const Mat& bottom_blob, const Mat& reference_blob, int& _woffset, int& _hoffset, int& _doffset, int& _coffset, int& _outw, int& _outh, int& _outd, int& _outc) const
570 {
571 int channels = bottom_blob.c;
572 int dims = bottom_blob.dims;
573
574 int ref_w = reference_blob.w;
575 int ref_h = reference_blob.h;
576 int ref_d = reference_blob.d;
577 int ref_channels = reference_blob.c;
578 int ref_dims = reference_blob.dims;
579
580 if (dims == 1)
581 {
582 _woffset = woffset;
583 _outw = ref_w;
584 }
585 if (dims == 2)
586 {
587 _woffset = woffset;
588 _hoffset = hoffset;
589 _outw = ref_w;
590 _outh = ref_h;
591 }
592 if (dims == 3)
593 {
594 _woffset = woffset;
595 _hoffset = hoffset;
596 _coffset = coffset;
597 _outw = ref_w;
598 _outh = ref_h;
599 _outc = ref_dims == 3 ? ref_channels : channels;
600 }
601 if (dims == 4)
602 {
603 _woffset = woffset;
604 _hoffset = hoffset;
605 _doffset = doffset;
606 _coffset = coffset;
607 _outw = ref_w;
608 _outh = ref_h;
609 _outd = ref_d;
610 _outc = ref_dims == 4 ? ref_channels : channels;
611 }
612 }
613
resolve_crop_roi(const Mat & bottom_blob,const int * param_data,int & _woffset,int & _hoffset,int & _doffset,int & _coffset,int & _outw,int & _outh,int & _outd,int & _outc) const614 void Crop::resolve_crop_roi(const Mat& bottom_blob, const int* param_data, int& _woffset, int& _hoffset, int& _doffset, int& _coffset, int& _outw, int& _outh, int& _outd, int& _outc) const
615 {
616 int dims = bottom_blob.dims;
617
618 if (dims == 1)
619 {
620 _woffset = param_data[0];
621 _outw = param_data[3];
622 }
623 if (dims == 2)
624 {
625 _woffset = param_data[0];
626 _hoffset = param_data[1];
627 _outw = param_data[3];
628 _outh = param_data[4];
629 }
630 if (dims == 3)
631 {
632 _woffset = param_data[0];
633 _hoffset = param_data[1];
634 _coffset = param_data[2];
635 _outw = param_data[3];
636 _outh = param_data[4];
637 _outc = param_data[5];
638 }
639 if (dims == 4)
640 {
641 _woffset = param_data[0];
642 _hoffset = param_data[1];
643 _doffset = param_data[2];
644 _coffset = param_data[3];
645 _outw = param_data[4];
646 _outh = param_data[5];
647 _outd = param_data[6];
648 _outc = param_data[7];
649 }
650 }
651
652 } // namespace ncnn
653