Compute Library
 21.02
NEChannelExtractKernel.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-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  */
25 
26 #include "arm_compute/core/Error.h"
33 #include "arm_compute/core/Types.h"
39 
40 #include <arm_neon.h>
41 
42 using namespace arm_compute;
43 
44 namespace arm_compute
45 {
46 class Coordinates;
47 } // namespace arm_compute
48 
50  : _func(nullptr), _lut_index(0)
51 {
52 }
53 
55 {
56  ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
57  ARM_COMPUTE_ERROR_ON(input == output);
58 
60 
61  // Check if input tensor has a valid format
64 
67 
68  // Check if channel is valid for given format
69  const Format format = input->info()->format();
71 
72  unsigned int subsampling = 1;
73 
74  if(format == Format::YUYV422 || format == Format::UYVY422)
75  {
76  // Check if the width of the tensor shape is even for formats with subsampled channels (UYVY422 and YUYV422)
78 
79  if(channel != Channel::Y)
80  {
81  subsampling = 2;
82  }
83  }
84 
87 
89 
90  _input = input;
91  _output = output;
92  _lut_index = channel_idx_from_format(format, channel);
93 
94  unsigned int num_elems_processed_per_iteration = 16;
95 
96  if(format == Format::YUYV422 || format == Format::UYVY422)
97  {
98  _func = &NEChannelExtractKernel::extract_1C_from_2C_img;
99 
100  if(channel != Channel::Y) // Channel::U or Channel::V
101  {
102  num_elems_processed_per_iteration = 32;
103  _func = &NEChannelExtractKernel::extract_YUYV_uv;
104  }
105  }
106  else // Format::RGB888 or Format::RGBA8888
107  {
108  _func = &NEChannelExtractKernel::extract_1C_from_3C_img;
109 
110  if(format == Format::RGBA8888)
111  {
112  _func = &NEChannelExtractKernel::extract_1C_from_4C_img;
113  }
114  }
115 
116  Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
117 
119  AccessWindowRectangle output_access(output->info(), 0, 0, num_elems_processed_per_iteration, 1, 1.f / subsampling, 1.f / subsampling);
120  update_window_and_padding(win, input_access, output_access);
121 
122  ValidRegion input_valid_region = input->info()->valid_region();
123  output_access.set_valid_region(win, ValidRegion(input_valid_region.anchor, output->info()->tensor_shape()));
124 
125  INEKernel::configure(win);
126 }
127 
129 {
130  ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
132 
134 
135  const Format format = input->info()->format();
137 
138  // Get input plane
139  const IImage *input_plane = input->plane(plane_idx_from_channel(format, channel));
140  ARM_COMPUTE_ERROR_ON_NULLPTR(input_plane);
141 
142  if(Channel::Y == channel && format != Format::YUV444)
143  {
144  // Check if the width of the tensor shape is even for formats with subsampled channels (UYVY422 and YUYV422)
145  ARM_COMPUTE_ERROR_ON_TENSORS_NOT_EVEN(format, input_plane);
146  }
147 
148  // Calculate 2x2 subsampled tensor shape
149  TensorShape output_shape = calculate_subsampled_shape(input->plane(0)->info()->tensor_shape(), format, channel);
150  set_shape_if_empty(*output->info(), output_shape);
151 
153 
154  // Check if input tensor has a valid format
157 
158  _input = input_plane;
159  _output = output;
160  _lut_index = channel_idx_from_format(format, channel);
161 
162  unsigned int num_elems_processed_per_iteration = 32;
163 
165 
166  if((format == Format::NV12 || format == Format::NV21) && channel != Channel::Y)
167  {
168  num_elems_processed_per_iteration = 16;
169  _func = &NEChannelExtractKernel::extract_1C_from_2C_img;
170  }
171 
172  Window win = calculate_max_window(*_input->info(), Steps(num_elems_processed_per_iteration));
173 
174  AccessWindowHorizontal input_access(_input->info(), 0, num_elems_processed_per_iteration);
176  update_window_and_padding(win, input_access, output_access);
177  output_access.set_valid_region(win, _input->info()->valid_region());
178 
179  INEKernel::configure(win);
180 }
181 
183 {
184  ARM_COMPUTE_UNUSED(info);
187  ARM_COMPUTE_ERROR_ON(_func == nullptr);
188 
189  (this->*_func)(window);
190 }
191 
192 void NEChannelExtractKernel::extract_1C_from_2C_img(const Window &win)
193 {
194  Iterator in(_input, win);
195  Iterator out(_output, win);
196 
197  execute_window_loop(win, [&](const Coordinates &)
198  {
199  const auto in_ptr = static_cast<uint8_t *>(in.ptr());
200  const auto out_ptr = static_cast<uint8_t *>(out.ptr());
201  const auto pixels = vld2q_u8(in_ptr);
202  vst1q_u8(out_ptr, pixels.val[_lut_index]);
203  },
204  in, out);
205 }
206 
207 void NEChannelExtractKernel::extract_1C_from_3C_img(const Window &win)
208 {
209  Iterator in(_input, win);
210  Iterator out(_output, win);
211 
212  execute_window_loop(win, [&](const Coordinates &)
213  {
214  const auto in_ptr = static_cast<uint8_t *>(in.ptr());
215  const auto out_ptr = static_cast<uint8_t *>(out.ptr());
216  const auto pixels = vld3q_u8(in_ptr);
217  vst1q_u8(out_ptr, pixels.val[_lut_index]);
218  },
219  in, out);
220 }
221 
222 void NEChannelExtractKernel::extract_1C_from_4C_img(const Window &win)
223 {
224  Iterator in(_input, win);
225  Iterator out(_output, win);
226 
227  execute_window_loop(win, [&](const Coordinates &)
228  {
229  const auto in_ptr = static_cast<uint8_t *>(in.ptr());
230  const auto out_ptr = static_cast<uint8_t *>(out.ptr());
231  const auto pixels = vld4q_u8(in_ptr);
232  vst1q_u8(out_ptr, pixels.val[_lut_index]);
233  },
234  in, out);
235 }
236 
237 void NEChannelExtractKernel::extract_YUYV_uv(const Window &win)
238 {
239  ARM_COMPUTE_ERROR_ON(win.x().step() % 2);
240 
241  Window win_out(win);
242  win_out.set_dimension_step(Window::DimX, win.x().step() / 2);
243 
244  Iterator in(_input, win);
245  Iterator out(_output, win_out);
246 
247  execute_window_loop(win, [&](const Coordinates &)
248  {
249  const auto in_ptr = static_cast<uint8_t *>(in.ptr());
250  const auto out_ptr = static_cast<uint8_t *>(out.ptr());
251  const auto pixels = vld4q_u8(in_ptr);
252  vst1q_u8(out_ptr, pixels.val[_lut_index]);
253  },
254  in, out);
255 }
256 
258 {
259  Iterator in(_input, win);
260  Iterator out(_output, win);
261 
262  execute_window_loop(win, [&](const Coordinates &)
263  {
264  const auto in_ptr = static_cast<uint8_t *>(in.ptr());
265  const auto out_ptr = static_cast<uint8_t *>(out.ptr());
266  vst4_u8(out_ptr, vld4_u8(in_ptr));
267  },
268  in, out);
269 }
bool set_format_if_unknown(ITensorInfo &info, Format format)
Set the format, data type and number of channels to the specified value if the current data type is u...
A single plane of 32-bit macro pixel of U0, Y0, V0, Y1 byte.
Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps, bool skip_border, BorderSize border_size)
const Window & window() const
The maximum window the kernel can be executed on.
Definition: IKernel.cpp:28
Shape of a tensor.
Definition: TensorShape.h:39
int plane_idx_from_channel(Format format, Channel channel)
Return the plane index of a given channel given an input format.
Definition: Utils.h:262
TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel=Channel::UNKNOWN)
Calculate subsampled shape for a given format and channel.
Definition: Utils.h:774
#define ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(t)
Definition: Validate.h:856
constexpr int step() const
Return the step of the dimension.
Definition: Window.h:104
1 channel, 1 U8 per channel
void run(const Window &window, const ThreadInfo &info) override
Execute the kernel on the passed window.
#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
A 2 plane YUV format of Luma (Y) and interleaved UV data at 4:2:0 sampling.
#define ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(t,...)
Definition: Validate.h:643
Interface for Neon tensor.
Definition: ITensor.h:36
A 2 plane YUV format of Luma (Y) and interleaved VU data at 4:2:0 sampling.
Copyright (c) 2017-2021 Arm Limited.
virtual ValidRegion valid_region() const =0
Valid region of the tensor.
3 channels, 1 U8 per channel
#define ARM_COMPUTE_ERROR_ON_TENSORS_NOT_EVEN(...)
Definition: Validate.h:318
Implementation of a rectangular access pattern.
virtual Format format() const =0
Colour format of the image.
static constexpr size_t DimX
Alias for dimension 0 also known as X dimension.
Definition: Window.h:43
bool update_window_and_padding(Window &win, Ts &&... patterns)
Update window and padding size for each of the access patterns.
Definition: WindowHelpers.h:46
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
Interface for multi-planar images.
Definition: IMultiImage.h:34
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
Channel
Available channels.
Definition: Types.h:487
Format
Image colour formats.
Definition: Types.h:54
Class to describe a number of elements in each dimension.
Definition: Steps.h:40
Coordinates of an item.
Definition: Coordinates.h:37
Implementation of a row access pattern.
A 3 plane of 8 bit 4:4:4 sampled Y, U, V planes.
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor&#39;s metadata.
bool set_shape_if_empty(ITensorInfo &info, const TensorShape &shape)
Set the shape to the specified value if the current assignment is empty.
constexpr uint8_t * ptr() const
Return a pointer to the current pixel.
Definition: Helpers.inl:139
__kernel void copy_plane(__global uchar *src_ptr, uint src_stride_x, uint src_step_x, uint src_stride_y, uint src_step_y, uint src_offset_first_element_in_bytes, __global uchar *dst_ptr, uint dst_stride_x, uint dst_step_x, uint dst_stride_y, uint dst_step_y, uint dst_offset_first_element_in_bytes)
This function extracts a given plane from an multi-planar image.
virtual const MultiImageInfo * info() const =0
Interface to be implemented by the child class to return the multi-planar image&#39;s metadata...
#define ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(k)
Definition: Validate.h:941
void configure(const ITensor *input, Channel channel, ITensor *output)
Set the input and output of the kernel.
A 3 plane of 8-bit 4:2:0 sampled Y, U, V planes.
4 channels, 1 U8 per channel
ScaleKernelInfo info(interpolation_policy, default_border_mode, PixelValue(), sampling_policy, false)
Information about executing thread and CPU.
Definition: CPPTypes.h:235
#define ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(...)
Definition: Validate.h:286
virtual IImage * plane(unsigned int index)=0
Return a pointer to the requested plane of the image.
unsigned int num_elems_processed_per_iteration
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
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
Container for valid region of a window.
Definition: Types.h:188
A single plane of 32-bit macro pixel of Y0, U0, Y1, V0 bytes.
Iterator updated by execute_window_loop for each window element.
Definition: Helpers.h:46
Format format() const
Colour format of the image.
Describe a multidimensional execution window.
Definition: Window.h:39
Coordinates anchor
Anchor for the start of the valid region.
Definition: Types.h:260
#define ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(f, s)
Definition: Validate.h:205
int channel_idx_from_format(Format format, Channel channel)
Return the channel index of a given channel given an input format.
Definition: Utils.h:327
constexpr const Dimension & x() const
Alias to access the first dimension of the window.
Definition: Window.h:145
#define ARM_COMPUTE_ERROR_ON_CHANNEL_NOT_IN_KNOWN_FORMAT(f, c)
Definition: Validate.h:903