Compute Library
 21.02
NEScale.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2021 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  */
25 
27 #include "arm_compute/core/Error.h"
36 
38 
39 #include "support/Rounding.h"
40 
41 #include <cmath>
42 #include <cstddef>
43 #include <utility>
44 
45 namespace arm_compute
46 {
47 namespace
48 {
49 void precompute_dx_dy_offsets(ITensor *dx, ITensor *dy, ITensor *offsets, float wr, float hr, SamplingPolicy sampling_policy, bool align_corners)
50 {
51  ARM_COMPUTE_ERROR_ON(nullptr == offsets);
52  ARM_COMPUTE_UNUSED(sampling_policy);
53  float sampling_offset = 0.0f;
54  if(sampling_policy == SamplingPolicy::CENTER)
55  {
56  sampling_offset = 0.5f;
57  }
58 
59  Window win;
60  win.set(Window::DimX, Window::Dimension(0, offsets->info()->dimension(0), 1));
61  win.set(Window::DimY, Window::Dimension(0, offsets->info()->dimension(1), 1));
62 
63  if(dx != nullptr && dy != nullptr)
64  {
65  // Pre-compute the offset and pixel's distance for BILINEAR interpolation
66  Iterator offsets_it(offsets, win);
67  Iterator dx_it(dx, win);
68  Iterator dy_it(dy, win);
69 
70  execute_window_loop(win, [&](const Coordinates & id)
71  {
72  const float in_x = (id.x() + sampling_offset) * wr - sampling_offset;
73  const float in_y = (id.y() + sampling_offset) * hr - sampling_offset;
74  const int in_xi = std::floor(in_x);
75  const int in_yi = std::floor(in_y);
76 
77  *reinterpret_cast<int32_t *>(offsets_it.ptr()) = in_xi;
78  *reinterpret_cast<float *>(dx_it.ptr()) = in_x - in_xi;
79  *reinterpret_cast<float *>(dy_it.ptr()) = in_y - in_yi;
80  },
81  offsets_it, dx_it, dy_it);
82  }
83  else
84  {
85  // Pre-compute the offset for NEAREST interpolation
86  Iterator offsets_it(offsets, win);
87 
88  execute_window_loop(win, [&](const Coordinates & id)
89  {
90  const float float_in_xi = (id.x() + sampling_offset) * wr;
91  const auto in_xi = static_cast<size_t>(align_corners ? arm_compute::utils::rounding::round_half_away_from_zero(float_in_xi) : std::floor(float_in_xi));
92  *reinterpret_cast<int32_t *>(offsets_it.ptr()) = in_xi;
93  },
94  offsets_it);
95  }
96 }
97 } // namespace
98 
100  : _offsets(), _dx(), _dy()
101 {
102 }
103 
105 {
106  ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
108 
110 
111  // Get data layout and width/height indices
115 
116  // Get the tensor shape
117  TensorShape shape(output->info()->dimension(idx_width));
118  shape.set(1, output->info()->dimension(idx_height), false);
119 
120  // Compute the ratio between source width/height and destination width/height
121  const auto wr = arm_compute::scale_utils::calculate_resize_ratio(input->info()->dimension(idx_width), output->info()->dimension(idx_width), is_align_corners_used);
122  const auto hr = arm_compute::scale_utils::calculate_resize_ratio(input->info()->dimension(idx_height), output->info()->dimension(idx_height), is_align_corners_used);
123 
124  // Area interpolation behaves as Nearest Neighbour in case of up-sampling
125  const auto policy_to_use = (info.interpolation_policy == InterpolationPolicy::AREA && wr <= 1.f && hr <= 1.f) ? InterpolationPolicy::NEAREST_NEIGHBOR : info.interpolation_policy;
126 
127  auto scale_kernel = std::make_unique<NEScaleKernel>();
128  switch(policy_to_use)
129  {
131  {
132  TensorInfo tensor_info_offsets(shape, Format::S32);
133  _offsets.allocator()->init(tensor_info_offsets);
134 
135  scale_kernel->configure(input, nullptr, nullptr, &_offsets, output, info);
136 
137  // Allocate once the configure methods have been called
138  _offsets.allocator()->allocate();
139 
140  // Pre-compute offsets for nearest interpolation
141  precompute_dx_dy_offsets(nullptr, nullptr, &_offsets, wr, hr, info.sampling_policy, is_align_corners_used);
142  break;
143  }
145  {
146  TensorInfo tensor_info_offsets(shape, Format::S32);
147  TensorInfo tensor_info_dxdy(shape, Format::F32);
148 
149  _offsets.allocator()->init(tensor_info_offsets);
150  _dx.allocator()->init(tensor_info_dxdy);
151  _dy.allocator()->init(tensor_info_dxdy);
152 
153  scale_kernel->configure(input, &_dx, &_dy, &_offsets, output, info);
154 
155  // Allocate once the configure methods have been called
156  _offsets.allocator()->allocate();
157  _dx.allocator()->allocate();
158  _dy.allocator()->allocate();
159 
160  // Pre-compute dx, dy and offsets for bilinear interpolation
161  precompute_dx_dy_offsets(&_dx, &_dy, &_offsets, wr, hr, info.sampling_policy, is_align_corners_used);
162  break;
163  }
165  {
166  scale_kernel->configure(input, nullptr, nullptr, nullptr, output, info);
167  break;
168  }
169  default:
170  ARM_COMPUTE_ERROR("Unsupported interpolation mode");
171  }
172  _kernel = std::move(scale_kernel);
173 }
174 
176 {
179 
180  ITensorInfo *offsets = nullptr;
181  ITensorInfo *dx = nullptr;
182  ITensorInfo *dy = nullptr;
183 
184  // Get data layout and width/height indices
188 
189  // Get the tensor shape of auxilary buffers
190  const TensorShape shape(output->dimension(idx_width), output->dimension(idx_height));
191 
192  TensorInfo tensor_info_offsets(shape, Format::S32);
193  TensorInfo tensor_info_dx(shape, Format::F32);
194  TensorInfo tensor_info_dy(shape, Format::F32);
195 
196  switch(info.interpolation_policy)
197  {
199  offsets = &tensor_info_offsets;
200  break;
202  offsets = &tensor_info_offsets;
203  dx = &tensor_info_dx;
204  dy = &tensor_info_dy;
205  break;
206  default:
207  break;
208  }
209 
210  ARM_COMPUTE_RETURN_ON_ERROR(NEScaleKernel::validate(input->clone().get(), dx, dy, offsets, output->clone().get(), info));
211  return Status{};
212 }
213 } // namespace arm_compute
Shape of a tensor.
Definition: TensorShape.h:39
InterpolationPolicy interpolation_policy
Interpolation type to use.
void init(const TensorAllocator &allocator, const Coordinates &coords, TensorInfo &sub_info)
Shares the same backing memory with another tensor allocator, while the tensor info might be differen...
virtual size_t dimension(size_t index) const =0
Return the size of the requested dimension.
NEScale()
Constructor.
Definition: NEScale.cpp:99
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
#define ARM_COMPUTE_RETURN_ON_ERROR(status)
Checks if a status contains an error and returns it.
Definition: Error.h:204
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
const DataLayout data_layout
Definition: Im2Col.cpp:151
bool align_corners
Align corners of input and output.
Store the tensor&#39;s metadata.
Definition: ITensorInfo.h:40
#define ARM_COMPUTE_ERROR_THROW_ON(status)
Definition: Error.h:455
T round_half_away_from_zero(T value)
Round floating-point value with half value rounding away from zero.
Definition: Rounding.h:106
Status class.
Definition: Error.h:52
Output values are defined to match the source pixel whose center is nearest to the sample position...
#define ARM_COMPUTE_RETURN_ERROR_ON(cond)
If the condition is true, an error is returned.
Definition: Error.h:296
Interface for Neon tensor.
Definition: ITensor.h:36
Copyright (c) 2017-2021 Arm Limited.
Samples are taken at pixel center.
bool is_align_corners_allowed_sampling_policy(SamplingPolicy sampling_policy)
Returns if aligned corners are allowed for the given sampling policy.
Definition: ScaleUtils.h:52
TensorAllocator * allocator()
Return a pointer to the tensor&#39;s allocator.
Definition: Tensor.cpp:48
#define ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(...)
Definition: Validate.h:163
1 channel, 1 S32 per channel
static Status validate(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, const ITensorInfo *offsets, ITensorInfo *output, const ScaleKernelInfo &info)
Static function to check if given info will lead to a valid configuration of NEScaleKernel.
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ScaleKernelInfo &info)
Static function to check if given info will lead to a valid configuration of NEScale.
Definition: NEScale.cpp:175
static constexpr size_t DimX
Alias for dimension 0 also known as X dimension.
Definition: Window.h:43
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
SamplingPolicy sampling_policy
Sampling policy used by the interpolation.
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
virtual std::unique_ptr< T > clone() const =0
Provide a clone of the current object of class T.
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor&#39;s metadata.
Samples are taken at pixel top left corner.
void configure(ITensor *input, ITensor *output, const ScaleKernelInfo &info)
Initialize the function&#39;s source, destination, interpolation type and border_mode.
Definition: NEScale.cpp:104
Output values are determined by averaging the source pixels whose areas fall under the area of the de...
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
ScaleKernelInfo info(interpolation_policy, default_border_mode, PixelValue(), sampling_policy, false)
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
Store the tensor&#39;s metadata.
Definition: TensorInfo.h:45
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
float calculate_resize_ratio(size_t input_size, size_t output_size, bool align_corners=false)
Returns resize ratio between input and output with consideration of aligned corners.
Definition: ScaleUtils.cpp:27
size_t get_data_layout_dimension_index(const DataLayout data_layout, const DataLayoutDimension data_layout_dimension)
Get the index of the given dimension.
Definition: Helpers.inl:193
DataLayout data_layout
Data layout to use.
DataLayout
[DataLayout enum definition]
Definition: Types.h:120
SamplingPolicy
Available Sampling Policies.
Definition: Types.h:102
virtual DataLayout data_layout() const =0
Get the data layout of the tensor.