Compute Library
 21.08
ColorConvertHelper.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-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  */
24 #ifndef ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H
25 #define ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H
26 
27 #include "Utils.h"
28 
29 namespace arm_compute
30 {
31 namespace test
32 {
33 namespace colorconvert_helper
34 {
35 namespace detail
36 {
37 constexpr float red_coef_bt709 = 1.5748F;
38 constexpr float green_coef_bt709 = -0.1873f;
39 constexpr float green_coef2_bt709 = -0.4681f;
40 constexpr float blue_coef_bt709 = 1.8556f;
41 
42 constexpr float rgb2yuv_bt709_kr = 0.2126f;
43 constexpr float rgb2yuv_bt709_kb = 0.0722f;
44 // K_g = 1 - K_r - K_b
45 constexpr float rgb2yuv_bt709_kg = 0.7152f;
46 // C_u = 1 / (2 * (1 - K_b))
47 constexpr float rgb2yuv_bt709_cu = 0.5389f;
48 // C_v = 1 / (2 * (1 - K_r))
49 constexpr float rgb2yuv_bt709_cv = 0.6350f;
50 
51 constexpr float rgb2u8_red_coef = 0.2126f;
52 constexpr float rgb2u8_green_coef = 0.7152f;
53 constexpr float rgb2u8_blue_coef = 0.0722f;
54 
55 template <typename T>
57 {
58  int width = src.shape().x();
59  int height = src.shape().y();
60 
61  for(int y = 0; y < height; ++y)
62  {
63  for(int x = 0; x < width; ++x)
64  {
65  const Coordinates src_coord{ x, y };
66  const Coordinates vec_coord{ x, y };
67 
68  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
69  auto *rvec_pixel = reinterpret_cast<T *>(rvec(vec_coord));
70  auto *gvec_pixel = reinterpret_cast<T *>(gvec(vec_coord));
71  auto *bvec_pixel = reinterpret_cast<T *>(bvec(vec_coord));
72 
73  rvec_pixel[0] = src_pixel[0]; // NOLINT
74  gvec_pixel[0] = src_pixel[1];
75  bvec_pixel[0] = src_pixel[2];
76  }
77  }
78 }
79 
80 template <typename T>
81 inline void rgb_to_yuv_calculation(const SimpleTensor<T> rvec, const SimpleTensor<T> gvec, const SimpleTensor<T> bvec, SimpleTensor<T> &yvec, SimpleTensor<T> &uvec_top, SimpleTensor<T> &uvec_bottom,
82  SimpleTensor<T> &vvec_top, SimpleTensor<T> &vvec_bottom)
83 {
84  int width = rvec.shape().x();
85  int height = rvec.shape().y();
86 
87  int uvec_coord_x = 0;
88  int uvec_coord_y = 0;
89  Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
90 
91  for(int y = 0; y < height; ++y)
92  {
93  for(int x = 0; x < width; x += 2)
94  {
95  Coordinates coord{ x, y };
96  auto *yvec_pixel = reinterpret_cast<T *>(yvec(coord));
97  auto *uvec_top_pixel = reinterpret_cast<T *>(uvec_top(uvec_coord));
98  auto *uvec_bottom_pixel = reinterpret_cast<T *>(uvec_bottom(uvec_coord));
99  auto *vvec_top_pixel = reinterpret_cast<T *>(vvec_top(uvec_coord));
100  auto *vvec_bottom_pixel = reinterpret_cast<T *>(vvec_bottom(uvec_coord));
101 
102  T border_value(0);
103  int rvec_val = validation::tensor_elem_at(rvec, coord, BorderMode::CONSTANT, border_value);
104  int gvec_val = validation::tensor_elem_at(gvec, coord, BorderMode::CONSTANT, border_value);
105  int bvec_val = validation::tensor_elem_at(bvec, coord, BorderMode::CONSTANT, border_value);
106  float result = rvec_val * rgb2yuv_bt709_kr + gvec_val * rgb2yuv_bt709_kg + bvec_val * rgb2yuv_bt709_kb;
107 
108  yvec_pixel[0] = result;
109  uvec_top_pixel[0] = (bvec_val - result) * rgb2yuv_bt709_cu + 128.f;
110  vvec_top_pixel[0] = (rvec_val - result) * rgb2yuv_bt709_cv + 128.f;
111 
112  coord.set(0, x + 1);
113  rvec_val = validation::tensor_elem_at(rvec, coord, BorderMode::CONSTANT, border_value);
114  gvec_val = validation::tensor_elem_at(gvec, coord, BorderMode::CONSTANT, border_value);
115  bvec_val = validation::tensor_elem_at(bvec, coord, BorderMode::CONSTANT, border_value);
116  result = rvec_val * rgb2yuv_bt709_kr + gvec_val * rgb2yuv_bt709_kg + bvec_val * rgb2yuv_bt709_kb;
117 
118  yvec_pixel[1] = result;
119  uvec_bottom_pixel[0] = (bvec_val - result) * rgb2yuv_bt709_cu + 128.f;
120  vvec_bottom_pixel[0] = (rvec_val - result) * rgb2yuv_bt709_cv + 128.f;
121 
122  uvec_coord.set(0, ++uvec_coord_x);
123  }
124  }
125 }
126 inline float compute_rgb_value(int y_value, int v_value, int u_value, unsigned char channel_idx)
127 {
128  float result = 0.f;
129  switch(channel_idx)
130  {
131  case 0:
132  {
133  const float red = (v_value - 128.f) * red_coef_bt709;
134  result = y_value + red;
135  break;
136  }
137  case 1:
138  {
139  const float green = (u_value - 128.f) * green_coef_bt709 + (v_value - 128.f) * green_coef2_bt709;
140  result = y_value + green;
141  break;
142  }
143  case 2:
144  {
145  const float blue = (u_value - 128.f) * blue_coef_bt709;
146  result = y_value + blue;
147  break;
148  }
149  default:
150  {
151  //Assuming Alpha channel
152  return 255;
153  }
154  }
155  return std::min(std::max(0.f, result), 255.f);
156 }
157 
158 template <typename T>
159 inline void yuyv_to_rgb_calculation(const SimpleTensor<T> yvec, const SimpleTensor<T> vvec, const SimpleTensor<T> yyvec, const SimpleTensor<T> uvec, SimpleTensor<T> &dst)
160 {
161  const int dst_width = dst.shape().x();
162  const int dst_height = dst.shape().y();
163  for(int y = 0; y < dst_height; ++y)
164  {
165  int x_coord = 0;
166  for(int x = 0; x < dst_width; x += 2, ++x_coord)
167  {
168  const Coordinates dst_coord{ x, y };
169  auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
170  const T border_value(0);
171  const int yvec_val = validation::tensor_elem_at(yvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
172  const int vvec_val = validation::tensor_elem_at(vvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
173  const int yyvec_val = validation::tensor_elem_at(yyvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
174  const int uvec_val = validation::tensor_elem_at(uvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
175  //Compute first RGB value using Y plane
176  for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
177  {
178  const float channel_value = compute_rgb_value(yvec_val, vvec_val, uvec_val, channel_idx);
179  dst_pixel[channel_idx] = channel_value;
180  }
181  //Compute second RGB value using YY plane
182  const Coordinates dst_coord2
183  {
184  x + 1, y
185  };
186  dst_pixel = reinterpret_cast<T *>(dst(dst_coord2));
187  for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
188  {
189  const float channel_value = compute_rgb_value(yyvec_val, vvec_val, uvec_val, channel_idx);
190  dst_pixel[channel_idx] = channel_value;
191  }
192  }
193  }
194 }
195 
196 template <typename T>
198 {
199  for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
200  {
201  const int width = dst.shape().x();
202  const int height = dst.shape().y();
203 
204  for(int y = 0; y < height; ++y)
205  {
206  for(int x = 0; x < width; ++x)
207  {
208  const Coordinates src_coord{ x, y };
209  const Coordinates dst_coord{ x, y };
210 
211  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
212  auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
213  if(channel_idx == 3)
214  {
215  dst_pixel[channel_idx] = 255;
216  continue;
217  }
218 
219  dst_pixel[channel_idx] = src_pixel[channel_idx];
220  }
221  }
222  }
223 }
224 
225 template <typename T>
227 {
228  const int width = dst.shape().x();
229  const int height = dst.shape().y();
230 
231  for(int y = 0; y < height; ++y)
232  {
233  for(int x = 0; x < width; ++x)
234  {
235  const Coordinates src_coord{ x, y };
236  const Coordinates dst_coord{ x, y };
237 
238  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
239  auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
240 
241  const float result = rgb2u8_red_coef * src_pixel[0] + rgb2u8_green_coef * src_pixel[1] + rgb2u8_blue_coef * src_pixel[2];
242 
243  dst_pixel[0] = utility::clamp<float>(result, 0, 255);
244  }
245  }
246 }
247 
248 template <typename T>
250 {
251  for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
252  {
253  const int width = dst.shape().x();
254  const int height = dst.shape().y();
255 
256  for(int y = 0; y < height; ++y)
257  {
258  for(int x = 0; x < width; ++x)
259  {
260  const Coordinates src_coord{ x, y };
261  const Coordinates dst_coord{ x, y };
262 
263  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
264  auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
265 
266  dst_pixel[channel_idx] = src_pixel[channel_idx];
267  }
268  }
269  }
270 }
271 
272 template <typename T>
274 {
275  SimpleTensor<T> yvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
276  SimpleTensor<T> uvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
277  SimpleTensor<T> yyvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
278  SimpleTensor<T> vvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
279 
280  const int step_x = (Format::YUYV422 == format || Format::UYVY422 == format) ? 2 : 1;
281  const int offset = (Format::YUYV422 == format) ? 0 : 1;
282 
283  Coordinates elem_coord{ 0, 0 };
284  const int width = yvec.shape().x();
285  const int height = yvec.shape().y();
286 
287  for(int y = 0; y < height; ++y)
288  {
289  for(int x = 0; x < width; ++x)
290  {
291  const Coordinates src_coord{ x * step_x, y };
292  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
293  auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord));
294  auto *uvec_pixel = reinterpret_cast<T *>(uvec(elem_coord));
295  auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord));
296  auto *vvec_pixel = reinterpret_cast<T *>(vvec(elem_coord));
297  yvec_pixel[x] = src_pixel[0 + offset];
298  uvec_pixel[x] = src_pixel[1 - offset];
299  yyvec_pixel[x] = src_pixel[2 + offset];
300  vvec_pixel[x] = src_pixel[3 - offset];
301  }
302  elem_coord.set(1, y + 1);
303  }
304 
305  yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst);
306 }
307 
308 template <typename T>
309 inline void colorconvert_iyuv_to_rgb(const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst)
310 {
311  SimpleTensor<T> yvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
312  SimpleTensor<T> uvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
313  SimpleTensor<T> yyvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
314  SimpleTensor<T> vvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
315 
316  Coordinates elem_coord{ 0, 0 };
317  const int yvec_width = yvec.shape().x();
318  const int yvec_height = yvec.shape().y();
319 
320  for(int y = 0; y < yvec_height; ++y)
321  {
322  for(int x = 0; x < yvec_width; ++x)
323  {
324  const Coordinates src_coord{ x, y };
325  const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[0](src_coord));
326  auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord));
327  auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord));
328  yvec_pixel[x] = src_pixel[x];
329  yyvec_pixel[x] = src_pixel[x + 1];
330  }
331  elem_coord.set(1, y + 1);
332  }
333 
334  const int uvec_width = uvec.shape().x();
335  const int uvec_height = uvec.shape().y();
336 
337  Coordinates top_elem_coord{ 0, 0 };
338  Coordinates bottom_elem_coord{ 0, 1 };
339  for(int y = 0; y < uvec_height; y += 2)
340  {
341  for(int x = 0; x < uvec_width; ++x)
342  {
343  const Coordinates src_coord{ x, y / 2 };
344  const auto *u_pixel = reinterpret_cast<const T *>(tensor_planes[1](src_coord));
345  const auto *v_pixel = reinterpret_cast<const T *>(tensor_planes[2](src_coord));
346  auto *uvec_pixel_top = reinterpret_cast<T *>(uvec(top_elem_coord));
347  auto *vvec_pixel_top = reinterpret_cast<T *>(vvec(top_elem_coord));
348 
349  auto *uvec_pixel_bottom = reinterpret_cast<T *>(uvec(bottom_elem_coord));
350  auto *vvec_pixel_bottom = reinterpret_cast<T *>(vvec(bottom_elem_coord));
351  uvec_pixel_top[x] = u_pixel[0];
352  vvec_pixel_top[x] = v_pixel[0];
353  uvec_pixel_bottom[x] = u_pixel[0];
354  vvec_pixel_bottom[x] = v_pixel[0];
355  }
356  top_elem_coord.set(1, y + 2);
357  bottom_elem_coord.set(1, top_elem_coord.y() + 1);
358  }
359 
360  yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst);
361 }
362 
363 template <typename T>
364 inline void colorconvert_nv12_to_rgb(const Format format, const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst)
365 {
366  SimpleTensor<T> yvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
367  SimpleTensor<T> uvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
368  SimpleTensor<T> yyvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
369  SimpleTensor<T> vvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
370 
371  const int offset = (Format::NV12 == format) ? 0 : 1;
372 
373  Coordinates elem_coord{ 0, 0 };
374  const int yvec_width = yvec.shape().x();
375  const int yvec_height = yvec.shape().y();
376 
377  for(int y = 0; y < yvec_height; ++y)
378  {
379  for(int x = 0; x < yvec_width; ++x)
380  {
381  const Coordinates src_coord{ x, y };
382  const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[0](src_coord));
383  auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord));
384  auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord));
385  yvec_pixel[x] = src_pixel[x];
386  yyvec_pixel[x] = src_pixel[x + 1];
387  }
388  elem_coord.set(1, y + 1);
389  }
390 
391  const int uvec_width = uvec.shape().x();
392  const int uvec_height = uvec.shape().y();
393 
394  Coordinates top_elem_coord{ 0, 0 };
395  Coordinates bottom_elem_coord{ 0, 1 };
396  for(int y = 0; y < uvec_height; y += 2)
397  {
398  for(int x = 0; x < uvec_width; ++x)
399  {
400  const Coordinates src_coord{ x, y / 2 };
401  const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[1](src_coord));
402  auto *uvec_pixel_top = reinterpret_cast<T *>(uvec(top_elem_coord));
403  auto *vvec_pixel_top = reinterpret_cast<T *>(vvec(top_elem_coord));
404 
405  auto *uvec_pixel_bottom = reinterpret_cast<T *>(uvec(bottom_elem_coord));
406  auto *vvec_pixel_bottom = reinterpret_cast<T *>(vvec(bottom_elem_coord));
407  uvec_pixel_top[x] = src_pixel[0 + offset];
408  vvec_pixel_top[x] = src_pixel[1 - offset];
409  uvec_pixel_bottom[x] = src_pixel[0 + offset];
410  vvec_pixel_bottom[x] = src_pixel[1 - offset];
411  }
412  top_elem_coord.set(1, y + 2);
413  bottom_elem_coord.set(1, top_elem_coord.y() + 1);
414  }
415 
416  yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst);
417 }
418 
419 template <typename T>
421 {
422  SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
423  SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
424  SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
425  SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
426 
427  int vec_shape_x = src.shape().x() * src.shape().y();
428 
429  SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
430  SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
431  SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
432  SimpleTensor<T> vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
433 
434  store_rgb_from_src(src, rvec, gvec, bvec);
435  rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom);
436 
437  SimpleTensor<T> utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
438  SimpleTensor<T> vtmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
439 
440  uint32_t utmp_width = utmp.shape().x();
441  uint32_t utmp_height = utmp.shape().y();
442 
443  uint32_t uvec_coord_x = 0;
444  uint32_t uvec_coord_y = 0;
445  Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
446  for(uint32_t y = 0; y < utmp_height; y++)
447  {
448  for(uint32_t x = 0; x < utmp_width; x++)
449  {
450  Coordinates coord{ x, y };
451  auto *utmp_pixel = reinterpret_cast<T *>(utmp(coord));
452  auto *vtmp_pixel = reinterpret_cast<T *>(vtmp(coord));
453 
454  T border_value(0);
455  int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
456  int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
457  int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
458  int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
459 
460  utmp_pixel[0] = std::ceil(float(uvec_top_val + uvec_bottom_val) / 2);
461  vtmp_pixel[0] = std::ceil(float(vvec_top_val + vvec_bottom_val) / 2);
462 
463  uvec_coord.set(0, ++uvec_coord_x);
464  }
465  }
466 
467  uint32_t second_plane_x = dst[1].shape().x();
468  uint32_t second_plane_y = dst[1].shape().y();
469 
470  uint32_t utmp_coord_x = 0;
471  uint32_t utmp_coord_y = 0;
472 
473  for(uint32_t y = 0; y < second_plane_y; y++)
474  {
475  for(uint32_t x = 0; x < second_plane_x; x++)
476  {
477  Coordinates coord{ x, y };
478  Coordinates utmp_top_coord{ utmp_coord_x, utmp_coord_y };
479  Coordinates utmp_bottom_coord{ utmp_coord_x, utmp_coord_y + 1 };
480 
481  auto *dst_pixel = reinterpret_cast<T *>(dst[1](coord));
482 
483  T border_value(0);
484  int utmp_top_val = validation::tensor_elem_at(utmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
485  int utmp_bottom_val = validation::tensor_elem_at(utmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
486 
487  int result = (utmp_top_val + utmp_bottom_val) / 2;
488  dst_pixel[0] = result;
489 
490  int vtmp_top_val = validation::tensor_elem_at(vtmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
491  int vtmp_bottom_val = validation::tensor_elem_at(vtmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
492 
493  result = (vtmp_top_val + vtmp_bottom_val) / 2;
494  dst_pixel[1] = result;
495 
496  utmp_coord_x++;
497 
498  if(utmp_coord_x >= utmp_width)
499  {
500  utmp_coord_x = 0;
501  utmp_coord_y += 2;
502  }
503  }
504  }
505 }
506 
507 template <typename T>
509 {
510  SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
511  SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
512  SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
513  SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
514 
515  int vec_shape_x = src.shape().x() * src.shape().y();
516 
517  SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
518  SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
519  SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
520  SimpleTensor<T> vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
521 
522  store_rgb_from_src(src, rvec, gvec, bvec);
523  rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom);
524 
525  SimpleTensor<T> utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
526  SimpleTensor<T> vtmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
527  uint32_t utmp_width = utmp.shape().x();
528  uint32_t utmp_height = utmp.shape().y();
529 
530  uint32_t uvec_coord_x = 0;
531  uint32_t uvec_coord_y = 0;
532  Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
533  for(uint32_t y = 0; y < utmp_height; y++)
534  {
535  for(uint32_t x = 0; x < utmp_width; x++)
536  {
537  Coordinates coord{ x, y };
538  auto *utmp_pixel = reinterpret_cast<T *>(utmp(coord));
539  auto *vtmp_pixel = reinterpret_cast<T *>(vtmp(coord));
540 
541  T border_value(0);
542  int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
543  int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
544  int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
545  int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
546 
547  utmp_pixel[0] = std::ceil(float(uvec_top_val + uvec_bottom_val) / 2);
548  vtmp_pixel[0] = std::ceil(float(vvec_top_val + vvec_bottom_val) / 2);
549 
550  uvec_coord.set(0, ++uvec_coord_x);
551  }
552  }
553 
554  uint32_t second_plane_x = dst[1].shape().x();
555  uint32_t second_plane_y = dst[1].shape().y();
556 
557  uint32_t utmp_coord_x = 0;
558  uint32_t utmp_coord_y = 0;
559 
560  for(uint32_t y = 0; y < second_plane_y; y++)
561  {
562  for(uint32_t x = 0; x < second_plane_x; x++)
563  {
564  Coordinates coord{ x, y };
565  Coordinates utmp_top_coord{ utmp_coord_x, utmp_coord_y };
566  Coordinates utmp_bottom_coord{ utmp_coord_x, utmp_coord_y + 1 };
567 
568  auto *u_pixel = reinterpret_cast<T *>(dst[1](coord));
569  auto *v_pixel = reinterpret_cast<T *>(dst[2](coord));
570 
571  T border_value(0);
572  int utmp_top_val = validation::tensor_elem_at(utmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
573  int utmp_bottom_val = validation::tensor_elem_at(utmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
574 
575  int result = (utmp_top_val + utmp_bottom_val) / 2;
576  u_pixel[0] = result;
577 
578  int vtmp_top_val = validation::tensor_elem_at(vtmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
579  int vtmp_bottom_val = validation::tensor_elem_at(vtmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
580 
581  result = (vtmp_top_val + vtmp_bottom_val) / 2;
582  v_pixel[0] = result;
583 
584  utmp_coord_x++;
585 
586  if(utmp_coord_x >= utmp_width)
587  {
588  utmp_coord_x = 0;
589  utmp_coord_y += 2;
590  }
591  }
592  }
593 }
594 
595 template <typename T>
597 {
598  SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
599  SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
600  SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
601  SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
602 
603  int vec_shape_x = src.shape().x() * src.shape().y();
604 
605  SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
606  SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
607  SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
608  SimpleTensor<T> vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
609 
610  int width = src.shape().x();
611  int height = src.shape().y();
612 
613  store_rgb_from_src(src, rvec, gvec, bvec);
614 
615  rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom);
616 
617  Coordinates uvec_coord{ 0, 0 };
618  for(int y = 0; y < height; y++)
619  {
620  for(int x = 0; x < width; x += 2)
621  {
622  Coordinates coord{ x, y };
623  auto *plane_1_pixel = reinterpret_cast<T *>(dst[1](coord));
624  auto *plane_2_pixel = reinterpret_cast<T *>(dst[2](coord));
625 
626  T border_value(0);
627  int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
628  int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
629 
630  plane_1_pixel[0] = uvec_top_val;
631  plane_1_pixel[1] = uvec_bottom_val;
632 
633  int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
634  int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
635 
636  plane_2_pixel[0] = vvec_top_val;
637  plane_2_pixel[1] = vvec_bottom_val;
638 
639  uvec_coord.increment(0);
640  }
641  }
642 }
643 
644 template <typename T>
645 inline void colorconvert_yuyv_to_nv12(const SimpleTensor<T> src, const Format format, std::vector<SimpleTensor<T>> &dst)
646 {
647  SimpleTensor<T> uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
648  SimpleTensor<T> uvvec_bottom(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
649 
650  const int offset = (Format::YUYV422 == format) ? 0 : 1;
651 
652  int width = dst[0].shape().x();
653  int height = dst[0].shape().y();
654 
655  for(int y = 0; y < height; ++y)
656  {
657  for(int x = 0; x < width; x++)
658  {
659  const Coordinates dst_coord{ x, y };
660  const Coordinates uv_coord{ x, y / 2 };
661 
662  const auto *src_pixel = reinterpret_cast<const T *>(src(dst_coord));
663  auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
664  auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
665  auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
666 
667  y_pixel[0] = src_pixel[0 + offset];
668 
669  if(y % 2 == 0)
670  {
671  uvvec_top_pixel[0] = src_pixel[1 - offset];
672  }
673  else
674  {
675  uvvec_bottom_pixel[0] = src_pixel[1 - offset];
676  }
677  }
678  }
679 
680  width = dst[1].shape().x();
681  height = dst[1].shape().y();
682 
683  int uv_coord_x = 0;
684  int uv_coord_y = 0;
685 
686  for(int y = 0; y < height; ++y)
687  {
688  for(int x = 0; x < width; x++)
689  {
690  const Coordinates dst_coord{ x, y };
691  const Coordinates uv_coord{ uv_coord_x, uv_coord_y };
692 
693  auto *uv_pixel = reinterpret_cast<T *>(dst[1](dst_coord));
694  const auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
695  const auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
696 
697  uv_pixel[0] = (uvvec_top_pixel[0] + uvvec_bottom_pixel[0]) / 2;
698  uv_pixel[1] = (uvvec_top_pixel[1] + uvvec_bottom_pixel[1]) / 2;
699  uv_coord_x += 2;
700  }
701  uv_coord_x = 0;
702  uv_coord_y++;
703  }
704 }
705 
706 template <typename T>
707 inline void colorconvert_yuyv_to_iyuv(const SimpleTensor<T> src, const Format format, std::vector<SimpleTensor<T>> &dst)
708 {
709  SimpleTensor<T> uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
710  SimpleTensor<T> uvvec_bottom(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
711 
712  const int offset = (Format::YUYV422 == format) ? 0 : 1;
713 
714  int width = dst[0].shape().x();
715  int height = dst[0].shape().y();
716 
717  for(int y = 0; y < height; ++y)
718  {
719  for(int x = 0; x < width; x++)
720  {
721  const Coordinates dst_coord{ x, y };
722  const Coordinates uv_coord{ x, y / 2 };
723 
724  const auto *src_pixel = reinterpret_cast<const T *>(src(dst_coord));
725  auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
726  auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
727  auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
728 
729  y_pixel[0] = src_pixel[0 + offset];
730 
731  if(y % 2 == 0)
732  {
733  uvvec_top_pixel[0] = src_pixel[1 - offset];
734  }
735  else
736  {
737  uvvec_bottom_pixel[0] = src_pixel[1 - offset];
738  }
739  }
740  }
741 
742  width = dst[1].shape().x();
743  height = dst[1].shape().y();
744 
745  int uv_coord_x = 0;
746  int uv_coord_y = 0;
747 
748  for(int y = 0; y < height; ++y)
749  {
750  for(int x = 0; x < width; x++)
751  {
752  const Coordinates dst_coord{ x, y };
753  const Coordinates uv_coord{ uv_coord_x, uv_coord_y };
754 
755  auto *u_pixel = reinterpret_cast<T *>(dst[1](dst_coord));
756  auto *v_pixel = reinterpret_cast<T *>(dst[2](dst_coord));
757  const auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
758  const auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
759 
760  u_pixel[0] = (uvvec_top_pixel[0] + uvvec_bottom_pixel[0]) / 2;
761  v_pixel[0] = (uvvec_top_pixel[1] + uvvec_bottom_pixel[1]) / 2;
762  uv_coord_x += 2;
763  }
764  uv_coord_x = 0;
765  uv_coord_y++;
766  }
767 }
768 
769 template <typename T>
770 inline void nv_to_iyuv(const SimpleTensor<T> src, const Format src_format, SimpleTensor<T> &nv1, SimpleTensor<T> &nv2)
771 {
772  int width = src.shape().x();
773  int height = src.shape().y();
774 
775  const int offset = (Format::NV12 == src_format) ? 1 : 0;
776 
777  for(int y = 0; y < height; ++y)
778  {
779  for(int x = 0; x < width; x++)
780  {
781  const Coordinates src_coord{ x, y };
782  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
783  auto *u_pixel = reinterpret_cast<T *>(nv1(src_coord));
784  auto *v_pixel = reinterpret_cast<T *>(nv2(src_coord));
785 
786  u_pixel[0] = src_pixel[1 - offset];
787  v_pixel[0] = src_pixel[0 + offset];
788  }
789  }
790 }
791 
792 template <typename T>
793 inline void nv_to_yuv4(const SimpleTensor<T> src, const Format src_format, SimpleTensor<T> &nv1, SimpleTensor<T> &nv2)
794 {
795  int width = src.shape().x();
796  int height = src.shape().y();
797 
798  const int offset = (Format::NV12 == src_format) ? 1 : 0;
799 
800  for(int y = 0; y < height; ++y)
801  {
802  for(int x = 0; x < width; x++)
803  {
804  const Coordinates src_coord{ x, y };
805  Coordinates dst_coord{ x * 2, y * 2 };
806  const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
807  auto *u_pixel = reinterpret_cast<T *>(nv1(dst_coord));
808  auto *v_pixel = reinterpret_cast<T *>(nv2(dst_coord));
809 
810  u_pixel[0] = src_pixel[1 - offset];
811  u_pixel[1] = src_pixel[1 - offset];
812 
813  v_pixel[0] = src_pixel[0 + offset];
814  v_pixel[1] = src_pixel[0 + offset];
815 
816  dst_coord.set(1, y * 2 + 1);
817  u_pixel = reinterpret_cast<T *>(nv1(dst_coord));
818  v_pixel = reinterpret_cast<T *>(nv2(dst_coord));
819  u_pixel[0] = src_pixel[1 - offset];
820  u_pixel[1] = src_pixel[1 - offset];
821 
822  v_pixel[0] = src_pixel[0 + offset];
823  v_pixel[1] = src_pixel[0 + offset];
824  }
825  }
826 }
827 
828 template <typename T>
829 inline void colorconvert_nv_to_iyuv(const std::vector<SimpleTensor<T>> src, const Format src_format, std::vector<SimpleTensor<T>> &dst)
830 {
831  int width = dst[0].shape().x();
832  int height = dst[0].shape().y();
833 
834  for(int y = 0; y < height; ++y)
835  {
836  for(int x = 0; x < width; ++x)
837  {
838  const Coordinates dst_coord{ x, y };
839 
840  const auto *src_pixel = reinterpret_cast<const T *>(src[0](dst_coord));
841  auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
842 
843  y_pixel[0] = src_pixel[0];
844  }
845  }
846 
847  nv_to_iyuv(src[1], src_format, dst[1], dst[2]);
848 }
849 
850 template <typename T>
851 inline void colorconvert_nv_to_yuv4(const std::vector<SimpleTensor<T>> src, const Format src_format, std::vector<SimpleTensor<T>> &dst)
852 {
853  int width = dst[0].shape().x();
854  int height = dst[0].shape().y();
855 
856  for(int y = 0; y < height; ++y)
857  {
858  for(int x = 0; x < width; ++x)
859  {
860  const Coordinates dst_coord{ x, y };
861 
862  const auto *src_pixel = reinterpret_cast<const T *>(src[0](dst_coord));
863  auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
864 
865  y_pixel[0] = src_pixel[0];
866  }
867  }
868 
869  nv_to_yuv4(src[1], src_format, dst[1], dst[2]);
870 }
871 
872 } // namespace detail
873 } // color_convert_helper
874 } // namespace test
875 } // namespace arm_compute
876 #endif /*ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H */
void set(size_t dimension, T value, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: Dimensions.h:76
__global uchar * offset(const Image *img, int x, int y)
Get the pointer position of a Image.
Definition: helpers.h:861
void store_rgb_from_src(const SimpleTensor< T > src, SimpleTensor< T > &rvec, SimpleTensor< T > &gvec, SimpleTensor< T > &bvec)
float compute_rgb_value(int y_value, int v_value, int u_value, unsigned char channel_idx)
A single plane of 32-bit macro pixel of U0, Y0, V0, Y1 byte.
T tensor_elem_at(const SimpleTensor< T > &src, Coordinates coord, BorderMode border_mode, T constant_border_value)
Definition: Utils.h:63
Shape of a tensor.
Definition: TensorShape.h:39
void colorconvert_yuyv_to_iyuv(const SimpleTensor< T > src, const Format format, std::vector< SimpleTensor< T >> &dst)
void colorconvert_nv_to_iyuv(const std::vector< SimpleTensor< T >> src, const Format src_format, std::vector< SimpleTensor< T >> &dst)
void nv_to_yuv4(const SimpleTensor< T > src, const Format src_format, SimpleTensor< T > &nv1, SimpleTensor< T > &nv2)
void colorconvert_yuyv_to_nv12(const SimpleTensor< T > src, const Format format, std::vector< SimpleTensor< T >> &dst)
1 channel, 1 U8 per channel
void colorconvert_yuyv_to_rgb(const SimpleTensor< T > src, const Format format, SimpleTensor< T > &dst)
A 2 plane YUV format of Luma (Y) and interleaved UV data at 4:2:0 sampling.
void colorconvert_nv_to_yuv4(const std::vector< SimpleTensor< T >> src, const Format src_format, std::vector< SimpleTensor< T >> &dst)
void colorconvert_iyuv_to_rgb(const std::vector< SimpleTensor< T >> &tensor_planes, SimpleTensor< T > &dst)
TensorShape shape() const override
Shape of the tensor.
Definition: SimpleTensor.h:320
void nv_to_iyuv(const SimpleTensor< T > src, const Format src_format, SimpleTensor< T > &nv1, SimpleTensor< T > &nv2)
SimpleTensor< float > src
Definition: DFT.cpp:155
Copyright (c) 2017-2021 Arm Limited.
T x() const
Alias to access the size of the first dimension.
Definition: Dimensions.h:87
void yuyv_to_rgb_calculation(const SimpleTensor< T > yvec, const SimpleTensor< T > vvec, const SimpleTensor< T > yyvec, const SimpleTensor< T > uvec, SimpleTensor< T > &dst)
void colorconvert_rgb_to_nv12(const SimpleTensor< T > src, std::vector< SimpleTensor< T >> &dst)
void colorconvert_rgbx_to_rgb(const SimpleTensor< T > src, SimpleTensor< T > &dst)
Format
Image colour formats.
Definition: Types.h:54
Coordinates of an item.
Definition: Coordinates.h:37
void rgb_to_yuv_calculation(const SimpleTensor< T > rvec, const SimpleTensor< T > gvec, const SimpleTensor< T > bvec, SimpleTensor< T > &yvec, SimpleTensor< T > &uvec_top, SimpleTensor< T > &uvec_bottom, SimpleTensor< T > &vvec_top, SimpleTensor< T > &vvec_bottom)
Simple tensor object that stores elements in a consecutive chunk of memory.
Definition: SimpleTensor.h:58
int num_channels() const override
Number of channels of the tensor.
Definition: SimpleTensor.h:370
void colorconvert_rgb_to_u8(const SimpleTensor< T > src, SimpleTensor< T > &dst)
void colorconvert_rgb_to_rgbx(const SimpleTensor< T > src, SimpleTensor< T > &dst)
void colorconvert_rgb_to_iyuv(const SimpleTensor< T > src, std::vector< SimpleTensor< T >> &dst)
void colorconvert_nv12_to_rgb(const Format format, const std::vector< SimpleTensor< T >> &tensor_planes, SimpleTensor< T > &dst)
void colorconvert_rgb_to_yuv4(const SimpleTensor< T > src, std::vector< SimpleTensor< T >> &dst)
A single plane of 32-bit macro pixel of Y0, U0, Y1, V0 bytes.