• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
store_rgb_from_src(const SimpleTensor<T> src,SimpleTensor<T> & rvec,SimpleTensor<T> & gvec,SimpleTensor<T> & bvec)56 inline void store_rgb_from_src(const SimpleTensor<T> src, SimpleTensor<T> &rvec, SimpleTensor<T> &gvec, SimpleTensor<T> &bvec)
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>
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)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 }
compute_rgb_value(int y_value,int v_value,int u_value,unsigned char channel_idx)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>
yuyv_to_rgb_calculation(const SimpleTensor<T> yvec,const SimpleTensor<T> vvec,const SimpleTensor<T> yyvec,const SimpleTensor<T> uvec,SimpleTensor<T> & dst)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>
colorconvert_rgb_to_rgbx(const SimpleTensor<T> src,SimpleTensor<T> & dst)197 inline void colorconvert_rgb_to_rgbx(const SimpleTensor<T> src, SimpleTensor<T> &dst)
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>
colorconvert_rgb_to_u8(const SimpleTensor<T> src,SimpleTensor<T> & dst)226 inline void colorconvert_rgb_to_u8(const SimpleTensor<T> src, SimpleTensor<T> &dst)
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>
colorconvert_rgbx_to_rgb(const SimpleTensor<T> src,SimpleTensor<T> & dst)249 inline void colorconvert_rgbx_to_rgb(const SimpleTensor<T> src, SimpleTensor<T> &dst)
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>
colorconvert_yuyv_to_rgb(const SimpleTensor<T> src,const Format format,SimpleTensor<T> & dst)273 inline void colorconvert_yuyv_to_rgb(const SimpleTensor<T> src, const Format format, SimpleTensor<T> &dst)
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>
colorconvert_iyuv_to_rgb(const std::vector<SimpleTensor<T>> & tensor_planes,SimpleTensor<T> & dst)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>
colorconvert_nv12_to_rgb(const Format format,const std::vector<SimpleTensor<T>> & tensor_planes,SimpleTensor<T> & dst)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>
colorconvert_rgb_to_nv12(const SimpleTensor<T> src,std::vector<SimpleTensor<T>> & dst)420 inline void colorconvert_rgb_to_nv12(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst)
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>
colorconvert_rgb_to_iyuv(const SimpleTensor<T> src,std::vector<SimpleTensor<T>> & dst)508 inline void colorconvert_rgb_to_iyuv(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst)
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>
colorconvert_rgb_to_yuv4(const SimpleTensor<T> src,std::vector<SimpleTensor<T>> & dst)596 inline void colorconvert_rgb_to_yuv4(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst)
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>
colorconvert_yuyv_to_nv12(const SimpleTensor<T> src,const Format format,std::vector<SimpleTensor<T>> & dst)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>
colorconvert_yuyv_to_iyuv(const SimpleTensor<T> src,const Format format,std::vector<SimpleTensor<T>> & dst)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>
nv_to_iyuv(const SimpleTensor<T> src,const Format src_format,SimpleTensor<T> & nv1,SimpleTensor<T> & nv2)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>
nv_to_yuv4(const SimpleTensor<T> src,const Format src_format,SimpleTensor<T> & nv1,SimpleTensor<T> & nv2)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>
colorconvert_nv_to_iyuv(const std::vector<SimpleTensor<T>> src,const Format src_format,std::vector<SimpleTensor<T>> & dst)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>
colorconvert_nv_to_yuv4(const std::vector<SimpleTensor<T>> src,const Format src_format,std::vector<SimpleTensor<T>> & dst)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 */
877