Compute Library
 20.02.1
NEColorConvertKernel.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2018 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"
34 #include "arm_compute/core/Types.h"
37 
38 using namespace arm_compute;
39 
41  : _input(nullptr), _output(nullptr), _func(nullptr)
42 {
43 }
44 
46 {
48 
49  set_shape_if_empty(*output->info(), input->info()->tensor_shape());
50 
52 
53  unsigned int num_elems_processed_per_iteration = 0;
54 
55  switch(input->info()->format())
56  {
57  case Format::RGBA8888:
58  {
59  switch(output->info()->format())
60  {
61  case Format::RGB888:
64  break;
65  default:
66  ARM_COMPUTE_ERROR("Not supported");
67  break;
68  }
69  break;
70  }
71  case Format::UYVY422:
72  {
73  switch(output->info()->format())
74  {
75  case Format::RGB888:
76  _func = colorconvert_yuyv_to_rgb<false, false>;
78  break;
79  case Format::RGBA8888:
80  _func = colorconvert_yuyv_to_rgb<false, true>;
82  break;
83  default:
84  ARM_COMPUTE_ERROR("Not supported");
85  break;
86  }
87  break;
88  }
89  case Format::YUYV422:
90  {
91  switch(output->info()->format())
92  {
93  case Format::RGB888:
94  _func = colorconvert_yuyv_to_rgb<true, false>;
96  break;
97  case Format::RGBA8888:
98  _func = colorconvert_yuyv_to_rgb<true, true>;
100  break;
101  default:
102  ARM_COMPUTE_ERROR("Not supported");
103  break;
104  }
105  break;
106  }
107  case Format::RGB888:
108  {
109  switch(output->info()->format())
110  {
111  case Format::RGBA8888:
112  _func = colorconvert_rgb_to_rgbx;
114  break;
115  case Format::U8:
116  _func = colorconvert_rgb_to_u8;
118  break;
119  default:
120  ARM_COMPUTE_ERROR("Not supported");
121  break;
122  }
123  break;
124  }
125  default:
126  ARM_COMPUTE_ERROR("Not supported");
127  break;
128  }
129 
130  _input = input;
131  _output = output;
132 
133  // Configure kernel window
137 
138  update_window_and_padding(win, input_access, output_access);
139 
140  output_access.set_valid_region(win, input->info()->valid_region());
141 
142  INEKernel::configure(win);
143 }
144 
146 {
149 
150  set_shape_if_empty(*output->info(), input->plane(0)->info()->tensor_shape());
151 
153 
154  unsigned int num_elems_processed_per_iteration = 0;
155 
156  switch(input->info()->format())
157  {
158  case Format::NV12:
159  {
160  switch(output->info()->format())
161  {
162  case Format::RGB888:
163  _func = colorconvert_nv12_to_rgb<true, false>;
165  break;
166  case Format::RGBA8888:
167  _func = colorconvert_nv12_to_rgb<true, true>;
169  break;
170  default:
171  ARM_COMPUTE_ERROR("Not supported");
172  break;
173  }
174  break;
175  }
176  case Format::NV21:
177  {
178  switch(output->info()->format())
179  {
180  case Format::RGB888:
181  _func = colorconvert_nv12_to_rgb<false, false>;
183  break;
184  case Format::RGBA8888:
185  _func = colorconvert_nv12_to_rgb<false, true>;
187  break;
188  default:
189  ARM_COMPUTE_ERROR("Not supported");
190  break;
191  }
192  break;
193  }
194  case Format::IYUV:
195  {
196  switch(output->info()->format())
197  {
198  case Format::RGB888:
199  _func = colorconvert_iyuv_to_rgb<false>;
201  break;
202  case Format::RGBA8888:
203  _func = colorconvert_iyuv_to_rgb<true>;
205  break;
206  default:
207  ARM_COMPUTE_ERROR("Not supported");
208  break;
209  }
210  break;
211  }
212  default:
213  ARM_COMPUTE_ERROR("Not supported");
214  break;
215  }
216 
217  _input = input;
218  _output = output;
219 
220  // Configure kernel window
223 
224  unsigned int input_plane_count = 3;
225 
226  if(input->info()->format() == Format::NV12 || input->info()->format() == Format::NV21)
227  {
228  input_plane_count = 2;
229  }
230 
231  AccessWindowHorizontal input0_access(input->plane(0)->info(), 0, num_elems_processed_per_iteration);
232  AccessWindowRectangle input1_access(input->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, 0.5f, 0.5f);
233  AccessWindowRectangle input2_access(input_plane_count == 2 ? nullptr : input->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, 0.5f, 0.5f);
235 
237  input0_access, input1_access, input2_access,
238  output_access);
239 
240  ValidRegion intersect_region = intersect_valid_regions(input->plane(0)->info()->valid_region(),
241  input->plane(1)->info()->valid_region());
242 
243  if(input_plane_count == 3)
244  {
245  intersect_region = intersect_valid_regions(intersect_region, input->plane(2)->info()->valid_region());
246  }
247 
248  output_access.set_valid_region(win, intersect_region);
249 
250  INEKernel::configure(win);
251 }
252 
254 {
257 
258  set_shape_if_empty(*output->plane(0)->info(), input->info()->tensor_shape());
259 
260  switch(output->info()->format())
261  {
262  case Format::NV12:
263  {
264  TensorShape subsampled_shape = input->info()->tensor_shape();
265  subsampled_shape.set(0, subsampled_shape[0] / 2);
266  subsampled_shape.set(1, subsampled_shape[1] / 2);
267 
268  set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
269 
270  ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
271  break;
272  }
273  case Format::IYUV:
274  {
275  TensorShape subsampled_shape = input->info()->tensor_shape();
276  subsampled_shape.set(0, subsampled_shape[0] / 2);
277  subsampled_shape.set(1, subsampled_shape[1] / 2);
278 
279  set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
280  set_shape_if_empty(*output->plane(2)->info(), subsampled_shape);
281 
282  ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
283  ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(2)->info()->tensor_shape());
284  break;
285  }
286  case Format::YUV444:
287  set_shape_if_empty(*output->plane(1)->info(), input->info()->tensor_shape());
288  set_shape_if_empty(*output->plane(2)->info(), input->info()->tensor_shape());
289 
292  break;
293  default:
294  ARM_COMPUTE_ERROR("Not supported");
295  }
296 
298 
299  unsigned int num_elems_processed_per_iteration = 0;
300 
301  switch(input->info()->format())
302  {
303  case Format::RGB888:
304  {
305  switch(output->info()->format())
306  {
307  case Format::NV12:
308  _func = colorconvert_rgb_to_nv12<false>;
310  break;
311  case Format::IYUV:
312  _func = colorconvert_rgb_to_iyuv<false>;
314  break;
315  case Format::YUV444:
316  _func = colorconvert_rgb_to_yuv4<false>;
318  break;
319  default:
320  ARM_COMPUTE_ERROR("Not supported");
321  break;
322  }
323  break;
324  }
325  case Format::RGBA8888:
326  {
327  switch(output->info()->format())
328  {
329  case Format::NV12:
330  _func = colorconvert_rgb_to_nv12<true>;
332  break;
333  case Format::IYUV:
334  _func = colorconvert_rgb_to_iyuv<true>;
336  break;
337  case Format::YUV444:
338  _func = colorconvert_rgb_to_yuv4<true>;
340  break;
341  default:
342  ARM_COMPUTE_ERROR("Not supported");
343  break;
344  }
345  break;
346  }
347  case Format::UYVY422:
348  {
349  switch(output->info()->format())
350  {
351  case Format::NV12:
352  _func = colorconvert_yuyv_to_nv12<false>;
354  break;
355  case Format::IYUV:
356  _func = colorconvert_yuyv_to_iyuv<false>;
358  break;
359  default:
360  ARM_COMPUTE_ERROR("Not supported");
361  break;
362  }
363  break;
364  }
365  case Format::YUYV422:
366  {
367  switch(output->info()->format())
368  {
369  case Format::NV12:
370  _func = colorconvert_yuyv_to_nv12<true>;
372  break;
373  case Format::IYUV:
374  _func = colorconvert_yuyv_to_iyuv<true>;
376  break;
377  default:
378  ARM_COMPUTE_ERROR("Not supported");
379  break;
380  }
381  break;
382  }
383  default:
384  ARM_COMPUTE_ERROR("Not supported");
385  break;
386  }
387 
388  _input = input;
389  _output = output;
390 
391  // Configure kernel window
393 
394  float sub_sampling = 1.f;
395 
396  if((input->info()->format() != Format::RGB888 || output->info()->format() != Format::YUV444) && (input->info()->format() != Format::RGBA8888 || output->info()->format() != Format::YUV444))
397  {
399  sub_sampling = 0.5f;
400  }
401 
402  unsigned int output_plane_count = 3;
403 
404  if(output->info()->format() == Format::NV12 || output->info()->format() == Format::NV21)
405  {
406  output_plane_count = 2;
407  }
408 
409  AccessWindowHorizontal output0_access(output->plane(0)->info(), 0, num_elems_processed_per_iteration);
410  AccessWindowRectangle output1_access(output->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, sub_sampling, sub_sampling);
411  AccessWindowRectangle output2_access(output_plane_count == 2 ? nullptr : output->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, sub_sampling, sub_sampling);
412 
415  output0_access,
416  output1_access,
417  output2_access);
418 
419  output0_access.set_valid_region(win, input->info()->valid_region());
420  output1_access.set_valid_region(win, input->info()->valid_region());
421  output2_access.set_valid_region(win, input->info()->valid_region());
422 
423  INEKernel::configure(win);
424 }
425 
427 {
429  ARM_COMPUTE_ERROR_ON(input == output);
430 
431  set_shape_if_empty(*output->plane(0)->info(), input->plane(0)->info()->tensor_shape());
432 
433  switch(output->info()->format())
434  {
435  case Format::NV12:
436  {
437  TensorShape subsampled_shape = input->plane(0)->info()->tensor_shape();
438  subsampled_shape.set(0, subsampled_shape[0] / 2);
439  subsampled_shape.set(1, subsampled_shape[1] / 2);
440 
441  set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
442 
443  ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
444  break;
445  }
446  case Format::IYUV:
447  {
448  TensorShape subsampled_shape = input->plane(0)->info()->tensor_shape();
449  subsampled_shape.set(0, subsampled_shape[0] / 2);
450  subsampled_shape.set(1, subsampled_shape[1] / 2);
451 
452  set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
453  set_shape_if_empty(*output->plane(2)->info(), subsampled_shape);
454 
455  ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
456  ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(2)->info()->tensor_shape());
457  break;
458  }
459  case Format::YUV444:
460  set_shape_if_empty(*output->plane(1)->info(), input->plane(0)->info()->tensor_shape());
461  set_shape_if_empty(*output->plane(2)->info(), input->plane(0)->info()->tensor_shape());
462 
463  ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(1));
464  ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(2));
465  break;
466  default:
467  ARM_COMPUTE_ERROR("Not supported");
468  }
469 
470  ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(0));
471 
472  switch(input->info()->format())
473  {
474  case Format::NV12:
475  {
476  switch(output->info()->format())
477  {
478  case Format::IYUV:
479  _func = colorconvert_nv12_to_iyuv<true>;
480  break;
481  case Format::YUV444:
482  _func = colorconvert_nv12_to_yuv4<true>;
483  break;
484  default:
485  ARM_COMPUTE_ERROR("Not supported");
486  break;
487  }
488  break;
489  }
490  case Format::NV21:
491  {
492  switch(output->info()->format())
493  {
494  case Format::IYUV:
495  _func = colorconvert_nv12_to_iyuv<false>;
496  break;
497  case Format::YUV444:
498  _func = colorconvert_nv12_to_yuv4<false>;
499  break;
500  default:
501  ARM_COMPUTE_ERROR("Not supported");
502  break;
503  }
504  break;
505  }
506  case Format::IYUV:
507  {
508  switch(output->info()->format())
509  {
510  case Format::NV12:
512  break;
513  case Format::YUV444:
515  break;
516  default:
517  ARM_COMPUTE_ERROR("Not supported");
518  break;
519  }
520  break;
521  }
522  default:
523  ARM_COMPUTE_ERROR("Not supported");
524  break;
525  }
526 
527  _input = input;
528  _output = output;
529 
530  constexpr unsigned int num_elems_processed_per_iteration = 32;
531  constexpr float input_sub_sampling = 0.5f;
532  const float output_sub_sampling = output->info()->format() == Format::YUV444 ? 1.f : 0.5f;
533 
534  // Configure kernel window
537 
538  unsigned int input_plane_count = 3;
539 
540  if(input->info()->format() == Format::NV12 || input->info()->format() == Format::NV21)
541  {
542  input_plane_count = 2;
543  }
544 
545  unsigned int output_plane_count = 3;
546 
547  if(output->info()->format() == Format::NV12 || output->info()->format() == Format::NV21)
548  {
549  output_plane_count = 2;
550  }
551 
552  AccessWindowHorizontal output0_access(output->plane(0)->info(), 0, num_elems_processed_per_iteration);
553  AccessWindowRectangle output1_access(output->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, output_sub_sampling, output_sub_sampling);
554  AccessWindowRectangle output2_access(output_plane_count == 2 ? nullptr : output->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, output_sub_sampling, output_sub_sampling);
555 
558  AccessWindowRectangle(input->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, input_sub_sampling, input_sub_sampling),
559  AccessWindowRectangle(input_plane_count == 2 ? nullptr : input->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, input_sub_sampling, input_sub_sampling),
560  output0_access,
561  output1_access,
562  output2_access);
563 
564  ValidRegion intersect_region = intersect_valid_regions(input->plane(0)->info()->valid_region(),
565  input->plane(1)->info()->valid_region());
566 
567  if(input_plane_count == 3)
568  {
569  intersect_region = intersect_valid_regions(intersect_region, input->plane(2)->info()->valid_region());
570  }
571 
572  output0_access.set_valid_region(win, intersect_region);
573  output1_access.set_valid_region(win, intersect_region);
574  output2_access.set_valid_region(win, intersect_region);
575 
576  INEKernel::configure(win);
577 }
578 
579 void NEColorConvertKernel::run(const Window &window, const ThreadInfo &info)
580 {
584  ARM_COMPUTE_ERROR_ON(_func == nullptr);
585 
586  (*_func)(_input, _output, window);
587 }
A single plane of 32-bit macro pixel of U0, Y0, V0, Y1 byte.
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
void colorconvert_iyuv_to_nv12(const void *__restrict input, void *__restrict output, const Window &win)
Convert IYUV to NV12.
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
1 channel, 1 U8 per channel
#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
void colorconvert_rgbx_to_rgb(const void *input, void *output, const Window &win)
Convert RGBX to RGB.
A 2 plane YUV format of Luma (Y) and interleaved UV data at 4:2:0 sampling.
Interface for NEON tensor.
Definition: ITensor.h:36
Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps=Steps(), bool skip_border=false, BorderSize border_size=BorderSize())
Calculate the maximum window for a given tensor shape and border setting.
Definition: Helpers.cpp:28
A 2 plane YUV format of Luma (Y) and interleaved VU data at 4:2:0 sampling.
Copyright (c) 2017-2020 ARM Limited.
#define ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(...)
Definition: Validate.h:441
void colorconvert_rgb_to_u8(const void *__restrict input, void *__restrict output, const Window &win)
Convert RGB to U8.
3 channels, 1 U8 per channel
#define ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(t)
Definition: Validate.h:856
Implementation of a rectangular access pattern.
virtual Format format() const =0
Colour format of the image.
void run(const Window &window, const ThreadInfo &info) override
Execute the kernel on the passed window.
bool update_window_and_padding(Window &win, Ts &&... patterns)
Update window and padding size for each of the access patterns.
Definition: Helpers.h:402
#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.
void colorconvert_rgb_to_rgbx(const void *__restrict input, void *__restrict output, const Window &win)
Convert RGB to RGBX.
Class to describe a number of elements in each dimension.
Definition: Steps.h:40
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's metadata.
#define ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(...)
Definition: Validate.h:286
ValidRegion intersect_valid_regions(const Ts &... regions)
Intersect multiple valid regions.
Definition: Helpers.h:503
virtual const MultiImageInfo * info() const =0
Interface to be implemented by the child class to return the multi-planar image's metadata.
A 3 plane of 8-bit 4:2:0 sampled Y, U, V planes.
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
4 channels, 1 U8 per channel
void set_dimension_step(size_t dimension, int step)
Set the step of a given dimension.
Definition: Window.inl:167
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
Information about executing thread and CPU.
Definition: CPPTypes.h:225
virtual IImage * plane(unsigned int index)=0
Return a pointer to the requested plane of the image.
bool set_shape_if_empty(ITensorInfo &info, const TensorShape &shape)
Set the shape to the specified value if the current assignment is empty.
Definition: Helpers.inl:235
void colorconvert_iyuv_to_yuv4(const void *__restrict input, void *__restrict output, const Window &win)
Convert IYUV to YUV4.
unsigned int num_elems_processed_per_iteration
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:78
Container for valid region of a window.
Definition: Types.h:184
A single plane of 32-bit macro pixel of Y0, U0, Y1, V0 bytes.
Format format() const
Colour format of the image.
void configure(const ITensor *input, ITensor *output)
Set the input and output of the kernel.
#define ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(f, s)
Definition: Validate.h:205
Describe a multidimensional execution window.
Definition: Window.h:39
#define ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(k)
Definition: Validate.h:941