blob: 8ab58409a768ebd8d3d57b5172b62a5505ce43b0 [file] [log] [blame]
Sanghoon Lee1fad27a2018-04-05 10:57:57 +01001/*
Giorgio Arenab309fc22021-01-05 09:46:16 +00002 * Copyright (c) 2017-2021 Arm Limited.
Sanghoon Lee1fad27a2018-04-05 10:57:57 +01003 *
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:
Michalis Spyrou6260e192019-06-06 13:47:38 +010012 *
Sanghoon Lee1fad27a2018-04-05 10:57:57 +010013 * 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
Michalis Spyrou6260e192019-06-06 13:47:38 +010019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Sanghoon Lee1fad27a2018-04-05 10:57:57 +010020 * 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 */
Michalis Spyrouf4643372019-11-29 16:17:13 +000024#ifndef ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H
25#define ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H
Sanghoon Lee1fad27a2018-04-05 10:57:57 +010026
27#include "Utils.h"
28
29namespace arm_compute
30{
31namespace test
32{
33namespace colorconvert_helper
34{
35namespace detail
36{
37constexpr float red_coef_bt709 = 1.5748F;
38constexpr float green_coef_bt709 = -0.1873f;
39constexpr float green_coef2_bt709 = -0.4681f;
40constexpr float blue_coef_bt709 = 1.8556f;
41
Sanghoon Leedec32a92018-06-29 10:52:57 +010042constexpr float rgb2yuv_bt709_kr = 0.2126f;
43constexpr float rgb2yuv_bt709_kb = 0.0722f;
44// K_g = 1 - K_r - K_b
45constexpr float rgb2yuv_bt709_kg = 0.7152f;
46// C_u = 1 / (2 * (1 - K_b))
47constexpr float rgb2yuv_bt709_cu = 0.5389f;
48// C_v = 1 / (2 * (1 - K_r))
49constexpr float rgb2yuv_bt709_cv = 0.6350f;
50
Manuel Bottini4284bfa2018-09-26 15:33:15 +010051constexpr float rgb2u8_red_coef = 0.2126f;
52constexpr float rgb2u8_green_coef = 0.7152f;
53constexpr float rgb2u8_blue_coef = 0.0722f;
54
Sanghoon Leedec32a92018-06-29 10:52:57 +010055template <typename T>
56inline 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
Michalis Spyrou6260e192019-06-06 13:47:38 +010073 rvec_pixel[0] = src_pixel[0]; // NOLINT
Sanghoon Leedec32a92018-06-29 10:52:57 +010074 gvec_pixel[0] = src_pixel[1];
75 bvec_pixel[0] = src_pixel[2];
76 }
77 }
78}
79
80template <typename T>
81inline 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}
Pablo Tello96fc1d62018-07-17 17:10:59 +0100126inline 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}
Sanghoon Leedec32a92018-06-29 10:52:57 +0100157
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100158template <typename T>
159inline 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();
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100163 for(int y = 0; y < dst_height; ++y)
164 {
165 int x_coord = 0;
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100166 for(int x = 0; x < dst_width; x += 2, ++x_coord)
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100167 {
Pablo Tello96fc1d62018-07-17 17:10:59 +0100168 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
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100176 for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
177 {
Pablo Tello96fc1d62018-07-17 17:10:59 +0100178 const float channel_value = compute_rgb_value(yvec_val, vvec_val, uvec_val, channel_idx);
179 dst_pixel[channel_idx] = channel_value;
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100180 }
Pablo Tello96fc1d62018-07-17 17:10:59 +0100181 //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));
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100187 for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
188 {
Pablo Tello96fc1d62018-07-17 17:10:59 +0100189 const float channel_value = compute_rgb_value(yyvec_val, vvec_val, uvec_val, channel_idx);
190 dst_pixel[channel_idx] = channel_value;
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100191 }
192 }
193 }
194}
195
196template <typename T>
197inline 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
225template <typename T>
Manuel Bottini4284bfa2018-09-26 15:33:15 +0100226inline 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
248template <typename T>
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100249inline 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
272template <typename T>
273inline void colorconvert_yuyv_to_rgb(const SimpleTensor<T> src, const Format format, SimpleTensor<T> &dst)
274{
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100275 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);
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100279
280 const int step_x = (Format::YUYV422 == format || Format::UYVY422 == format) ? 2 : 1;
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100281 const int offset = (Format::YUYV422 == format) ? 0 : 1;
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100282
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100283 Coordinates elem_coord{ 0, 0 };
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100284 const int width = yvec.shape().x();
285 const int height = yvec.shape().y();
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100286
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
308template <typename T>
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100309inline void colorconvert_iyuv_to_rgb(const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst)
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100310{
Pablo Tello14daf382018-06-12 16:09:24 +0100311 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);
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100315
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 };
Sanghoon Leedec32a92018-06-29 10:52:57 +0100344 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));
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100346 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));
Sanghoon Leedec32a92018-06-29 10:52:57 +0100351 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];
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100355 }
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
363template <typename T>
Michalis Spyrou6bff1952019-10-02 17:22:11 +0100364inline void colorconvert_nv12_to_rgb(const Format format, const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst)
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100365{
Pablo Tello14daf382018-06-12 16:09:24 +0100366 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);
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100370
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
Sanghoon Leedec32a92018-06-29 10:52:57 +0100419template <typename T>
420inline 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
Michalis Spyrou314598f2019-10-21 12:04:19 +0100440 uint32_t utmp_width = utmp.shape().x();
441 uint32_t utmp_height = utmp.shape().y();
Sanghoon Leedec32a92018-06-29 10:52:57 +0100442
Michalis Spyrou314598f2019-10-21 12:04:19 +0100443 uint32_t uvec_coord_x = 0;
444 uint32_t uvec_coord_y = 0;
Sanghoon Leedec32a92018-06-29 10:52:57 +0100445 Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
Michalis Spyrou314598f2019-10-21 12:04:19 +0100446 for(uint32_t y = 0; y < utmp_height; y++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100447 {
Michalis Spyrou314598f2019-10-21 12:04:19 +0100448 for(uint32_t x = 0; x < utmp_width; x++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100449 {
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
Michalis Spyrou314598f2019-10-21 12:04:19 +0100467 uint32_t second_plane_x = dst[1].shape().x();
468 uint32_t second_plane_y = dst[1].shape().y();
Sanghoon Leedec32a92018-06-29 10:52:57 +0100469
Michalis Spyrou314598f2019-10-21 12:04:19 +0100470 uint32_t utmp_coord_x = 0;
471 uint32_t utmp_coord_y = 0;
Sanghoon Leedec32a92018-06-29 10:52:57 +0100472
Michalis Spyrou314598f2019-10-21 12:04:19 +0100473 for(uint32_t y = 0; y < second_plane_y; y++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100474 {
Michalis Spyrou314598f2019-10-21 12:04:19 +0100475 for(uint32_t x = 0; x < second_plane_x; x++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100476 {
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
507template <typename T>
508inline 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);
Michalis Spyrou314598f2019-10-21 12:04:19 +0100527 uint32_t utmp_width = utmp.shape().x();
528 uint32_t utmp_height = utmp.shape().y();
Sanghoon Leedec32a92018-06-29 10:52:57 +0100529
Michalis Spyrou314598f2019-10-21 12:04:19 +0100530 uint32_t uvec_coord_x = 0;
531 uint32_t uvec_coord_y = 0;
Sanghoon Leedec32a92018-06-29 10:52:57 +0100532 Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
Michalis Spyrou314598f2019-10-21 12:04:19 +0100533 for(uint32_t y = 0; y < utmp_height; y++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100534 {
Michalis Spyrou314598f2019-10-21 12:04:19 +0100535 for(uint32_t x = 0; x < utmp_width; x++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100536 {
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
Michalis Spyrou314598f2019-10-21 12:04:19 +0100554 uint32_t second_plane_x = dst[1].shape().x();
555 uint32_t second_plane_y = dst[1].shape().y();
Sanghoon Leedec32a92018-06-29 10:52:57 +0100556
Michalis Spyrou314598f2019-10-21 12:04:19 +0100557 uint32_t utmp_coord_x = 0;
558 uint32_t utmp_coord_y = 0;
Sanghoon Leedec32a92018-06-29 10:52:57 +0100559
Michalis Spyrou314598f2019-10-21 12:04:19 +0100560 for(uint32_t y = 0; y < second_plane_y; y++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100561 {
Michalis Spyrou314598f2019-10-21 12:04:19 +0100562 for(uint32_t x = 0; x < second_plane_x; x++)
Sanghoon Leedec32a92018-06-29 10:52:57 +0100563 {
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
595template <typename T>
596inline 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
Giorgio Arena4d9383e2021-01-07 14:40:12 +0000617 Coordinates uvec_coord{ 0, 0 };
Sanghoon Leedec32a92018-06-29 10:52:57 +0100618 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
Giorgio Arenab309fc22021-01-05 09:46:16 +0000639 uvec_coord.increment(0);
Sanghoon Leedec32a92018-06-29 10:52:57 +0100640 }
641 }
642}
643
644template <typename T>
645inline 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
706template <typename T>
707inline 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
769template <typename T>
770inline 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
792template <typename T>
793inline 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
828template <typename T>
829inline 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
850template <typename T>
851inline 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
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100872} // namespace detail
873} // color_convert_helper
874} // namespace test
875} // namespace arm_compute
Michalis Spyrouf4643372019-11-29 16:17:13 +0000876#endif /*ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H */