Compute Library
 21.02
CropResize.cpp
Go to the documentation of this file.
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 {
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  {
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  }
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>
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>
161  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value)
162 {
163  ARM_COMPUTE_ERROR_ON(src.shape().num_dimensions() > 4);
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 
185  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
187  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
189  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
191  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
193  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
195  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
197  Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value);
198 } // namespace reference
199 } // namespace validation
200 } // namespace test
201 } // namespace arm_compute
__global uchar * offset(const Image *img, int x, int y)
Get the pointer position of a Image.
Definition: helpers.h:846
InterpolationPolicy
Interpolation method.
Definition: Types.h:392
T tensor_elem_at(const SimpleTensor< T > &src, Coordinates coord, BorderMode border_mode, T constant_border_value)
Definition: Utils.h:64
Shape of a tensor.
Definition: TensorShape.h:39
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
1 channel, 1 F32 per channel
Output values are defined by bilinear interpolation between the pixels.
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
TensorShape shape() const override
Shape of the tensor.
Definition: SimpleTensor.h:320
Output values are defined to match the source pixel whose center is nearest to the sample position...
bool is_valid_pixel_index(int x, int y, int width, int height, int border_size)
Checks if a pixel has valid coordinates.
Definition: Utils.h:54
SimpleTensor< float > src
Definition: DFT.cpp:155
Copyright (c) 2017-2021 Arm Limited.
int32_t x
X coordinates.
Definition: Types.h:465
SimpleTensor< float > crop_and_resize(const SimpleTensor< T > &src, const SimpleTensor< float > &boxes, SimpleTensor< int32_t > box_ind, Coordinates2D crop_size, InterpolationPolicy method, float extrapolation_value)
Definition: CropResize.cpp:160
Quantization information.
int32_t y
Y coordinates.
Definition: Types.h:466
Coordinates of an item.
Definition: Coordinates.h:37
DataLayout data_layout() const override
Data layout of the tensor.
Definition: SimpleTensor.h:351
void end(TokenStream &in, bool &valid)
Definition: MLGOParser.cpp:290
Simple tensor object that stores elements in a consecutive chunk of memory.
Definition: SimpleTensor.h:58
Coordinate type.
Definition: Types.h:463
Num samples, height, width, channels.
int num_elements() const override
Number of elements of the tensor.
Definition: SimpleTensor.h:406
void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators)
Iterate through the passed window, automatically adjusting the iterators and calling the lambda_funct...
Definition: Helpers.inl:77
const T * data() const
Constant pointer to the underlying buffer.
Definition: SimpleTensor.h:418