xref: /aosp_15_r20/external/ComputeLibrary/tests/validation/reference/CropResize.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2019-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "CropResize.h"
25 #include "Utils.h"
26 
27 namespace arm_compute
28 {
29 namespace test
30 {
31 namespace validation
32 {
33 namespace reference
34 {
35 namespace
36 {
scale_image(const SimpleTensor<float> & in,const TensorShape & out_shape,InterpolationPolicy policy,float extrapolation_value)37 SimpleTensor<float> scale_image(const SimpleTensor<float> &in, const TensorShape &out_shape, InterpolationPolicy policy, float extrapolation_value)
38 {
39     ARM_COMPUTE_ERROR_ON(in.data_layout() != DataLayout::NHWC);
40 
41     SimpleTensor<float> out{ out_shape, DataType::F32, 1, QuantizationInfo(), DataLayout::NHWC };
42     // Compute the ratio between source width/height and destination width/height
43     const auto wr = static_cast<float>(in.shape()[1]) / static_cast<float>(out_shape[1]);
44     const auto hr = static_cast<float>(in.shape()[2]) / static_cast<float>(out_shape[2]);
45 
46     const auto width  = static_cast<int>(in.shape().y());
47     const auto height = static_cast<int>(in.shape().z());
48 
49     Window win;
50     win.use_tensor_dimensions(out_shape);
51     execute_window_loop(win, [&](const Coordinates & out_id)
52     {
53         Coordinates in_id(out_id);
54         int         idw = in_id.y();
55         int         idh = in_id.z();
56 
57         switch(policy)
58         {
59             case InterpolationPolicy::NEAREST_NEIGHBOR:
60             {
61                 //Calculate the source coords without -0.5f is equivalent to round the x_scr/y_src coords
62                 float x_src = std::floor(idw * wr);
63                 float y_src = std::floor(idh * hr);
64                 in_id.set(1, x_src);
65                 in_id.set(2, y_src);
66 
67                 // If coordinates in range of tensor's width or height
68                 if(is_valid_pixel_index(x_src, y_src, width, height, 0))
69                 {
70                     *reinterpret_cast<float *>(out(out_id)) = tensor_elem_at(in, in_id, BorderMode::CONSTANT, extrapolation_value);
71                 }
72                 else
73                 {
74                     *reinterpret_cast<float *>(out(out_id)) = extrapolation_value;
75                 }
76                 break;
77             }
78             case InterpolationPolicy::BILINEAR:
79             {
80                 float x_src = idw * wr;
81                 float y_src = idh * hr;
82                 in_id.set(1, std::floor(x_src));
83                 in_id.set(2, std::floor(y_src));
84                 if(is_valid_pixel_index(x_src, y_src, width, height, 0))
85                 {
86                     const int id_w = in_id[1];
87                     const int id_h = in_id[2];
88 
89                     const float dx   = x_src - id_w;
90                     const float dy   = y_src - id_h;
91                     const float dx_1 = 1.0f - dx;
92                     const float dy_1 = 1.0f - dy;
93 
94                     in_id.set(1, id_w);
95                     in_id.set(2, id_h);
96                     const float tl = tensor_elem_at(in, in_id, BorderMode::CONSTANT, extrapolation_value);
97                     in_id.set(1, id_w + 1);
98                     in_id.set(2, id_h);
99                     const float tr = tensor_elem_at(in, in_id, BorderMode::CONSTANT, extrapolation_value);
100                     in_id.set(1, id_w);
101                     in_id.set(2, id_h + 1);
102                     const float bl = tensor_elem_at(in, in_id, BorderMode::CONSTANT, extrapolation_value);
103                     in_id.set(1, id_w + 1);
104                     in_id.set(2, id_h + 1);
105                     const float br = tensor_elem_at(in, in_id, BorderMode::CONSTANT, extrapolation_value);
106 
107                     *reinterpret_cast<float *>(out(out_id)) = tl * (dx_1 * dy_1) + tr * (dx * dy_1) + bl * (dx_1 * dy) + br * (dx * dy);
108                 }
109                 else
110                 {
111                     *reinterpret_cast<float *>(out(out_id)) = extrapolation_value;
112                 }
113                 break;
114             }
115             default:
116                 ARM_COMPUTE_ERROR("Unsupported interpolation mode");
117         }
118     });
119 
120     return out;
121 }
122 
123 template <typename T>
crop_image(const SimpleTensor<T> & src,Coordinates start,Coordinates end,int32_t batch_index,float extrapolation_value)124 SimpleTensor<float> crop_image(const SimpleTensor<T> &src, Coordinates start, Coordinates end, int32_t batch_index, float extrapolation_value)
125 {
126     TensorShape out_shape(src.shape()[0], static_cast<uint32_t>(abs(end[0] - start[0])) + 1, static_cast<uint32_t>(abs(end[1] - start[1])) + 1);
127 
128     SimpleTensor<float> out{ out_shape, DataType::F32, 1, QuantizationInfo(), DataLayout::NHWC };
129 
130     Window win;
131     win.use_tensor_dimensions(out_shape);
132     execute_window_loop(win, [&](const Coordinates & id)
133     {
134         bool        out_of_bounds = false;
135         Coordinates offset(id[0], 0, 0, batch_index);
136         for(uint32_t i = 1; i < 3; ++i)
137         {
138             offset.set(i, end[i - 1] < start[i - 1] ? start[i - 1] - id[i] : start[i - 1] + id[i]);
139             if(offset[i] < 0 || static_cast<uint32_t>(offset[i]) > src.shape()[i] - 1)
140             {
141                 out_of_bounds = true;
142                 break;
143             }
144         }
145         if(!out_of_bounds)
146         {
147             *reinterpret_cast<float *>(out(id)) = static_cast<float>(*reinterpret_cast<const T *>(src(offset)));
148         }
149         else
150         {
151             *reinterpret_cast<float *>(out(id)) = extrapolation_value;
152         }
153     });
154     return out;
155 }
156 
157 } // namespace
158 
159 template <typename T>
crop_and_resize(const SimpleTensor<T> & src,const SimpleTensor<float> & boxes,SimpleTensor<int32_t> box_ind,Coordinates2D crop_size,InterpolationPolicy method,float extrapolation_value)160 SimpleTensor<float> crop_and_resize(const SimpleTensor<T> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
161                                     Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value)
162 {
163     ARM_COMPUTE_ERROR_ON(src.shape().num_dimensions() > 4);
164     ARM_COMPUTE_ERROR_ON(src.data_layout() != DataLayout::NHWC);
165 
166     const TensorShape   out_shape(src.shape()[0], crop_size.x, crop_size.y, boxes.shape()[1]);
167     SimpleTensor<float> out{ out_shape, DataType::F32, 1, QuantizationInfo(), DataLayout::NHWC };
168 
169     const TensorShape scaled_image_shape(src.shape()[0], crop_size.x, crop_size.y);
170 
171     for(uint32_t i = 0; i < boxes.shape()[1]; ++i)
172     {
173         Coordinates start = Coordinates(std::floor((*reinterpret_cast<const float *>(boxes(Coordinates(1, i)))) * (src.shape()[1] - 1) + 0.5f),
174                                         std::floor((*reinterpret_cast<const float *>(boxes(Coordinates(0, i)))) * (src.shape()[2] - 1) + 0.5f));
175         Coordinates end = Coordinates(std::floor((*reinterpret_cast<const float *>(boxes(Coordinates(3, i)))) * (src.shape()[1] - 1) + 0.5f),
176                                       std::floor((*reinterpret_cast<const float *>(boxes(Coordinates(2, i)))) * (src.shape()[2] - 1) + 0.5f));
177         SimpleTensor<float> cropped = crop_image(src, start, end, box_ind[i], extrapolation_value);
178         SimpleTensor<float> scaled  = scale_image(cropped, scaled_image_shape, method, extrapolation_value);
179         std::copy_n(reinterpret_cast<float *>(scaled.data()), scaled.num_elements(), reinterpret_cast<float *>(out(Coordinates(0, 0, 0, i))));
180     }
181     return out;
182 }
183 
184 template SimpleTensor<float> crop_and_resize(const SimpleTensor<float> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
185                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
186 template SimpleTensor<float> crop_and_resize(const SimpleTensor<uint16_t> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
187                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
188 template SimpleTensor<float> crop_and_resize(const SimpleTensor<uint32_t> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
189                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
190 template SimpleTensor<float> crop_and_resize(const SimpleTensor<int16_t> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
191                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
192 template SimpleTensor<float> crop_and_resize(const SimpleTensor<int32_t> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
193                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
194 template SimpleTensor<float> crop_and_resize(const SimpleTensor<half> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
195                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
196 template SimpleTensor<float> crop_and_resize(const SimpleTensor<uint8_t> &src, const SimpleTensor<float> &boxes, SimpleTensor<int32_t> box_ind,
197                                              Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
198 } // namespace reference
199 } // namespace validation
200 } // namespace test
201 } // namespace arm_compute
202