blob: 7a8b547486cf5134241c933e0eb2b1c136b9f27f [file] [log] [blame]
Sanghoon Lee1fad27a2018-04-05 10:57:57 +01001/*
2 * Copyright (c) 2017-2018 ARM Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *asymm_int_mult
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, asymm_int_multDAMAGES 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
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
51template <typename T>
52inline void store_rgb_from_src(const SimpleTensor<T> src, SimpleTensor<T> &rvec, SimpleTensor<T> &gvec, SimpleTensor<T> &bvec)
53{
54 int width = src.shape().x();
55 int height = src.shape().y();
56
57 for(int y = 0; y < height; ++y)
58 {
59 for(int x = 0; x < width; ++x)
60 {
61 const Coordinates src_coord{ x, y };
62 const Coordinates vec_coord{ x, y };
63
64 const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
65 auto *rvec_pixel = reinterpret_cast<T *>(rvec(vec_coord));
66 auto *gvec_pixel = reinterpret_cast<T *>(gvec(vec_coord));
67 auto *bvec_pixel = reinterpret_cast<T *>(bvec(vec_coord));
68
69 rvec_pixel[0] = src_pixel[0];
70 gvec_pixel[0] = src_pixel[1];
71 bvec_pixel[0] = src_pixel[2];
72 }
73 }
74}
75
76template <typename T>
77inline 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,
78 SimpleTensor<T> &vvec_top, SimpleTensor<T> &vvec_bottom)
79{
80 int width = rvec.shape().x();
81 int height = rvec.shape().y();
82
83 int uvec_coord_x = 0;
84 int uvec_coord_y = 0;
85 Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
86
87 for(int y = 0; y < height; ++y)
88 {
89 for(int x = 0; x < width; x += 2)
90 {
91 Coordinates coord{ x, y };
92 auto *yvec_pixel = reinterpret_cast<T *>(yvec(coord));
93 auto *uvec_top_pixel = reinterpret_cast<T *>(uvec_top(uvec_coord));
94 auto *uvec_bottom_pixel = reinterpret_cast<T *>(uvec_bottom(uvec_coord));
95 auto *vvec_top_pixel = reinterpret_cast<T *>(vvec_top(uvec_coord));
96 auto *vvec_bottom_pixel = reinterpret_cast<T *>(vvec_bottom(uvec_coord));
97
98 T border_value(0);
99 int rvec_val = validation::tensor_elem_at(rvec, coord, BorderMode::CONSTANT, border_value);
100 int gvec_val = validation::tensor_elem_at(gvec, coord, BorderMode::CONSTANT, border_value);
101 int bvec_val = validation::tensor_elem_at(bvec, coord, BorderMode::CONSTANT, border_value);
102 float result = rvec_val * rgb2yuv_bt709_kr + gvec_val * rgb2yuv_bt709_kg + bvec_val * rgb2yuv_bt709_kb;
103
104 yvec_pixel[0] = result;
105 uvec_top_pixel[0] = (bvec_val - result) * rgb2yuv_bt709_cu + 128.f;
106 vvec_top_pixel[0] = (rvec_val - result) * rgb2yuv_bt709_cv + 128.f;
107
108 coord.set(0, x + 1);
109 rvec_val = validation::tensor_elem_at(rvec, coord, BorderMode::CONSTANT, border_value);
110 gvec_val = validation::tensor_elem_at(gvec, coord, BorderMode::CONSTANT, border_value);
111 bvec_val = validation::tensor_elem_at(bvec, coord, BorderMode::CONSTANT, border_value);
112 result = rvec_val * rgb2yuv_bt709_kr + gvec_val * rgb2yuv_bt709_kg + bvec_val * rgb2yuv_bt709_kb;
113
114 yvec_pixel[1] = result;
115 uvec_bottom_pixel[0] = (bvec_val - result) * rgb2yuv_bt709_cu + 128.f;
116 vvec_bottom_pixel[0] = (rvec_val - result) * rgb2yuv_bt709_cv + 128.f;
117
118 uvec_coord.set(0, ++uvec_coord_x);
119 }
120 }
121}
Pablo Tello96fc1d62018-07-17 17:10:59 +0100122inline float compute_rgb_value(int y_value, int v_value, int u_value, unsigned char channel_idx)
123{
124 float result = 0.f;
125 switch(channel_idx)
126 {
127 case 0:
128 {
129 const float red = (v_value - 128.f) * red_coef_bt709;
130 result = y_value + red;
131 break;
132 }
133 case 1:
134 {
135 const float green = (u_value - 128.f) * green_coef_bt709 + (v_value - 128.f) * green_coef2_bt709;
136 result = y_value + green;
137 break;
138 }
139 case 2:
140 {
141 const float blue = (u_value - 128.f) * blue_coef_bt709;
142 result = y_value + blue;
143 break;
144 }
145 default:
146 {
147 //Assuming Alpha channel
148 return 255;
149 }
150 }
151 return std::min(std::max(0.f, result), 255.f);
152}
Sanghoon Leedec32a92018-06-29 10:52:57 +0100153
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100154template <typename T>
155inline void yuyv_to_rgb_calculation(const SimpleTensor<T> yvec, const SimpleTensor<T> vvec, const SimpleTensor<T> yyvec, const SimpleTensor<T> uvec, SimpleTensor<T> &dst)
156{
157 const int dst_width = dst.shape().x();
158 const int dst_height = dst.shape().y();
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100159 for(int y = 0; y < dst_height; ++y)
160 {
161 int x_coord = 0;
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100162 for(int x = 0; x < dst_width; x += 2, ++x_coord)
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100163 {
Pablo Tello96fc1d62018-07-17 17:10:59 +0100164 const Coordinates dst_coord{ x, y };
165 auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
166 const T border_value(0);
167 const int yvec_val = validation::tensor_elem_at(yvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
168 const int vvec_val = validation::tensor_elem_at(vvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
169 const int yyvec_val = validation::tensor_elem_at(yyvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
170 const int uvec_val = validation::tensor_elem_at(uvec, { x_coord, y }, BorderMode::CONSTANT, border_value);
171 //Compute first RGB value using Y plane
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100172 for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
173 {
Pablo Tello96fc1d62018-07-17 17:10:59 +0100174 const float channel_value = compute_rgb_value(yvec_val, vvec_val, uvec_val, channel_idx);
175 dst_pixel[channel_idx] = channel_value;
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100176 }
Pablo Tello96fc1d62018-07-17 17:10:59 +0100177 //Compute second RGB value using YY plane
178 const Coordinates dst_coord2
179 {
180 x + 1, y
181 };
182 dst_pixel = reinterpret_cast<T *>(dst(dst_coord2));
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100183 for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
184 {
Pablo Tello96fc1d62018-07-17 17:10:59 +0100185 const float channel_value = compute_rgb_value(yyvec_val, vvec_val, uvec_val, channel_idx);
186 dst_pixel[channel_idx] = channel_value;
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100187 }
188 }
189 }
190}
191
192template <typename T>
193inline void colorconvert_rgb_to_rgbx(const SimpleTensor<T> src, SimpleTensor<T> &dst)
194{
195 for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
196 {
197 const int width = dst.shape().x();
198 const int height = dst.shape().y();
199
200 for(int y = 0; y < height; ++y)
201 {
202 for(int x = 0; x < width; ++x)
203 {
204 const Coordinates src_coord{ x, y };
205 const Coordinates dst_coord{ x, y };
206
207 const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
208 auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
209 if(channel_idx == 3)
210 {
211 dst_pixel[channel_idx] = 255;
212 continue;
213 }
214
215 dst_pixel[channel_idx] = src_pixel[channel_idx];
216 }
217 }
218 }
219}
220
221template <typename T>
222inline void colorconvert_rgbx_to_rgb(const SimpleTensor<T> src, SimpleTensor<T> &dst)
223{
224 for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx)
225 {
226 const int width = dst.shape().x();
227 const int height = dst.shape().y();
228
229 for(int y = 0; y < height; ++y)
230 {
231 for(int x = 0; x < width; ++x)
232 {
233 const Coordinates src_coord{ x, y };
234 const Coordinates dst_coord{ x, y };
235
236 const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
237 auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord));
238
239 dst_pixel[channel_idx] = src_pixel[channel_idx];
240 }
241 }
242 }
243}
244
245template <typename T>
246inline void colorconvert_yuyv_to_rgb(const SimpleTensor<T> src, const Format format, SimpleTensor<T> &dst)
247{
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100248 SimpleTensor<T> yvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
249 SimpleTensor<T> uvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
250 SimpleTensor<T> yyvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
251 SimpleTensor<T> vvec(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100252
253 const int step_x = (Format::YUYV422 == format || Format::UYVY422 == format) ? 2 : 1;
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100254 const int offset = (Format::YUYV422 == format) ? 0 : 1;
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100255
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100256 Coordinates elem_coord{ 0, 0 };
Georgios Pinitase8c18d42018-06-11 20:05:18 +0100257 const int width = yvec.shape().x();
258 const int height = yvec.shape().y();
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100259
260 for(int y = 0; y < height; ++y)
261 {
262 for(int x = 0; x < width; ++x)
263 {
264 const Coordinates src_coord{ x * step_x, y };
265 const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
266 auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord));
267 auto *uvec_pixel = reinterpret_cast<T *>(uvec(elem_coord));
268 auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord));
269 auto *vvec_pixel = reinterpret_cast<T *>(vvec(elem_coord));
270 yvec_pixel[x] = src_pixel[0 + offset];
271 uvec_pixel[x] = src_pixel[1 - offset];
272 yyvec_pixel[x] = src_pixel[2 + offset];
273 vvec_pixel[x] = src_pixel[3 - offset];
274 }
275 elem_coord.set(1, y + 1);
276 }
277
278 yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst);
279}
280
281template <typename T>
282inline void colorconvert_iyuv_to_rgb(const TensorShape &shape, const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst)
283{
Pablo Tello14daf382018-06-12 16:09:24 +0100284 SimpleTensor<T> yvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
285 SimpleTensor<T> uvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
286 SimpleTensor<T> yyvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
287 SimpleTensor<T> vvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100288
289 Coordinates elem_coord{ 0, 0 };
290 const int yvec_width = yvec.shape().x();
291 const int yvec_height = yvec.shape().y();
292
293 for(int y = 0; y < yvec_height; ++y)
294 {
295 for(int x = 0; x < yvec_width; ++x)
296 {
297 const Coordinates src_coord{ x, y };
298 const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[0](src_coord));
299 auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord));
300 auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord));
301 yvec_pixel[x] = src_pixel[x];
302 yyvec_pixel[x] = src_pixel[x + 1];
303 }
304 elem_coord.set(1, y + 1);
305 }
306
307 const int uvec_width = uvec.shape().x();
308 const int uvec_height = uvec.shape().y();
309
310 Coordinates top_elem_coord{ 0, 0 };
311 Coordinates bottom_elem_coord{ 0, 1 };
312 for(int y = 0; y < uvec_height; y += 2)
313 {
314 for(int x = 0; x < uvec_width; ++x)
315 {
316 const Coordinates src_coord{ x, y / 2 };
Sanghoon Leedec32a92018-06-29 10:52:57 +0100317 const auto *u_pixel = reinterpret_cast<const T *>(tensor_planes[1](src_coord));
318 const auto *v_pixel = reinterpret_cast<const T *>(tensor_planes[2](src_coord));
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100319 auto *uvec_pixel_top = reinterpret_cast<T *>(uvec(top_elem_coord));
320 auto *vvec_pixel_top = reinterpret_cast<T *>(vvec(top_elem_coord));
321
322 auto *uvec_pixel_bottom = reinterpret_cast<T *>(uvec(bottom_elem_coord));
323 auto *vvec_pixel_bottom = reinterpret_cast<T *>(vvec(bottom_elem_coord));
Sanghoon Leedec32a92018-06-29 10:52:57 +0100324 uvec_pixel_top[x] = u_pixel[0];
325 vvec_pixel_top[x] = v_pixel[0];
326 uvec_pixel_bottom[x] = u_pixel[0];
327 vvec_pixel_bottom[x] = v_pixel[0];
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100328 }
329 top_elem_coord.set(1, y + 2);
330 bottom_elem_coord.set(1, top_elem_coord.y() + 1);
331 }
332
333 yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst);
334}
335
336template <typename T>
337inline void colorconvert_nv12_to_rgb(const TensorShape &shape, const Format format, const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst)
338{
Pablo Tello14daf382018-06-12 16:09:24 +0100339 SimpleTensor<T> yvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
340 SimpleTensor<T> uvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
341 SimpleTensor<T> yyvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
342 SimpleTensor<T> vvec(TensorShape{ tensor_planes[0].shape().x() / 2, tensor_planes[0].shape().y() }, Format::U8);
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100343
344 const int offset = (Format::NV12 == format) ? 0 : 1;
345
346 Coordinates elem_coord{ 0, 0 };
347 const int yvec_width = yvec.shape().x();
348 const int yvec_height = yvec.shape().y();
349
350 for(int y = 0; y < yvec_height; ++y)
351 {
352 for(int x = 0; x < yvec_width; ++x)
353 {
354 const Coordinates src_coord{ x, y };
355 const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[0](src_coord));
356 auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord));
357 auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord));
358 yvec_pixel[x] = src_pixel[x];
359 yyvec_pixel[x] = src_pixel[x + 1];
360 }
361 elem_coord.set(1, y + 1);
362 }
363
364 const int uvec_width = uvec.shape().x();
365 const int uvec_height = uvec.shape().y();
366
367 Coordinates top_elem_coord{ 0, 0 };
368 Coordinates bottom_elem_coord{ 0, 1 };
369 for(int y = 0; y < uvec_height; y += 2)
370 {
371 for(int x = 0; x < uvec_width; ++x)
372 {
373 const Coordinates src_coord{ x, y / 2 };
374 const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[1](src_coord));
375 auto *uvec_pixel_top = reinterpret_cast<T *>(uvec(top_elem_coord));
376 auto *vvec_pixel_top = reinterpret_cast<T *>(vvec(top_elem_coord));
377
378 auto *uvec_pixel_bottom = reinterpret_cast<T *>(uvec(bottom_elem_coord));
379 auto *vvec_pixel_bottom = reinterpret_cast<T *>(vvec(bottom_elem_coord));
380 uvec_pixel_top[x] = src_pixel[0 + offset];
381 vvec_pixel_top[x] = src_pixel[1 - offset];
382 uvec_pixel_bottom[x] = src_pixel[0 + offset];
383 vvec_pixel_bottom[x] = src_pixel[1 - offset];
384 }
385 top_elem_coord.set(1, y + 2);
386 bottom_elem_coord.set(1, top_elem_coord.y() + 1);
387 }
388
389 yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst);
390}
391
Sanghoon Leedec32a92018-06-29 10:52:57 +0100392template <typename T>
393inline void colorconvert_rgb_to_nv12(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst)
394{
395 SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
396 SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
397 SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
398 SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
399
400 int vec_shape_x = src.shape().x() * src.shape().y();
401
402 SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
403 SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
404 SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
405 SimpleTensor<T> vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
406
407 store_rgb_from_src(src, rvec, gvec, bvec);
408 rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom);
409
410 SimpleTensor<T> utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
411 SimpleTensor<T> vtmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
412
413 int utmp_width = utmp.shape().x();
414 int utmp_height = utmp.shape().y();
415
416 int uvec_coord_x = 0;
417 int uvec_coord_y = 0;
418 Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
419 for(int y = 0; y < utmp_height; y++)
420 {
421 for(int x = 0; x < utmp_width; x++)
422 {
423 Coordinates coord{ x, y };
424 auto *utmp_pixel = reinterpret_cast<T *>(utmp(coord));
425 auto *vtmp_pixel = reinterpret_cast<T *>(vtmp(coord));
426
427 T border_value(0);
428 int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
429 int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
430 int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
431 int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
432
433 utmp_pixel[0] = std::ceil(float(uvec_top_val + uvec_bottom_val) / 2);
434 vtmp_pixel[0] = std::ceil(float(vvec_top_val + vvec_bottom_val) / 2);
435
436 uvec_coord.set(0, ++uvec_coord_x);
437 }
438 }
439
440 int second_plane_x = dst[1].shape().x();
441 int second_plane_y = dst[1].shape().y();
442
443 int utmp_coord_x = 0;
444 int utmp_coord_y = 0;
445
446 for(int y = 0; y < second_plane_y; y++)
447 {
448 for(int x = 0; x < second_plane_x; x++)
449 {
450 Coordinates coord{ x, y };
451 Coordinates utmp_top_coord{ utmp_coord_x, utmp_coord_y };
452 Coordinates utmp_bottom_coord{ utmp_coord_x, utmp_coord_y + 1 };
453
454 auto *dst_pixel = reinterpret_cast<T *>(dst[1](coord));
455
456 T border_value(0);
457 int utmp_top_val = validation::tensor_elem_at(utmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
458 int utmp_bottom_val = validation::tensor_elem_at(utmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
459
460 int result = (utmp_top_val + utmp_bottom_val) / 2;
461 dst_pixel[0] = result;
462
463 int vtmp_top_val = validation::tensor_elem_at(vtmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
464 int vtmp_bottom_val = validation::tensor_elem_at(vtmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
465
466 result = (vtmp_top_val + vtmp_bottom_val) / 2;
467 dst_pixel[1] = result;
468
469 utmp_coord_x++;
470
471 if(utmp_coord_x >= utmp_width)
472 {
473 utmp_coord_x = 0;
474 utmp_coord_y += 2;
475 }
476 }
477 }
478}
479
480template <typename T>
481inline void colorconvert_rgb_to_iyuv(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst)
482{
483 SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
484 SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
485 SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
486 SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
487
488 int vec_shape_x = src.shape().x() * src.shape().y();
489
490 SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
491 SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
492 SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
493 SimpleTensor<T> vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
494
495 store_rgb_from_src(src, rvec, gvec, bvec);
496 rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom);
497
498 SimpleTensor<T> utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
499 SimpleTensor<T> vtmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8);
500 int utmp_width = utmp.shape().x();
501 int utmp_height = utmp.shape().y();
502
503 int uvec_coord_x = 0;
504 int uvec_coord_y = 0;
505 Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
506 for(int y = 0; y < utmp_height; y++)
507 {
508 for(int x = 0; x < utmp_width; x++)
509 {
510 Coordinates coord{ x, y };
511 auto *utmp_pixel = reinterpret_cast<T *>(utmp(coord));
512 auto *vtmp_pixel = reinterpret_cast<T *>(vtmp(coord));
513
514 T border_value(0);
515 int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
516 int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
517 int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
518 int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
519
520 utmp_pixel[0] = std::ceil(float(uvec_top_val + uvec_bottom_val) / 2);
521 vtmp_pixel[0] = std::ceil(float(vvec_top_val + vvec_bottom_val) / 2);
522
523 uvec_coord.set(0, ++uvec_coord_x);
524 }
525 }
526
527 int second_plane_x = dst[1].shape().x();
528 int second_plane_y = dst[1].shape().y();
529
530 int utmp_coord_x = 0;
531 int utmp_coord_y = 0;
532
533 for(int y = 0; y < second_plane_y; y++)
534 {
535 for(int x = 0; x < second_plane_x; x++)
536 {
537 Coordinates coord{ x, y };
538 Coordinates utmp_top_coord{ utmp_coord_x, utmp_coord_y };
539 Coordinates utmp_bottom_coord{ utmp_coord_x, utmp_coord_y + 1 };
540
541 auto *u_pixel = reinterpret_cast<T *>(dst[1](coord));
542 auto *v_pixel = reinterpret_cast<T *>(dst[2](coord));
543
544 T border_value(0);
545 int utmp_top_val = validation::tensor_elem_at(utmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
546 int utmp_bottom_val = validation::tensor_elem_at(utmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
547
548 int result = (utmp_top_val + utmp_bottom_val) / 2;
549 u_pixel[0] = result;
550
551 int vtmp_top_val = validation::tensor_elem_at(vtmp, utmp_top_coord, BorderMode::CONSTANT, border_value);
552 int vtmp_bottom_val = validation::tensor_elem_at(vtmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value);
553
554 result = (vtmp_top_val + vtmp_bottom_val) / 2;
555 v_pixel[0] = result;
556
557 utmp_coord_x++;
558
559 if(utmp_coord_x >= utmp_width)
560 {
561 utmp_coord_x = 0;
562 utmp_coord_y += 2;
563 }
564 }
565 }
566}
567
568template <typename T>
569inline void colorconvert_rgb_to_yuv4(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst)
570{
571 SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
572 SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
573 SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
574 SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8);
575
576 int vec_shape_x = src.shape().x() * src.shape().y();
577
578 SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
579 SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
580 SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8);
581 SimpleTensor<T> vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8);
582
583 int width = src.shape().x();
584 int height = src.shape().y();
585
586 store_rgb_from_src(src, rvec, gvec, bvec);
587
588 rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom);
589
590 int uvec_coord_x = 0;
591 int uvec_coord_y = 0;
592 Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y };
593 for(int y = 0; y < height; y++)
594 {
595 for(int x = 0; x < width; x += 2)
596 {
597 Coordinates coord{ x, y };
598 auto *plane_1_pixel = reinterpret_cast<T *>(dst[1](coord));
599 auto *plane_2_pixel = reinterpret_cast<T *>(dst[2](coord));
600
601 T border_value(0);
602 int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
603 int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
604
605 plane_1_pixel[0] = uvec_top_val;
606 plane_1_pixel[1] = uvec_bottom_val;
607
608 int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value);
609 int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value);
610
611 plane_2_pixel[0] = vvec_top_val;
612 plane_2_pixel[1] = vvec_bottom_val;
613
614 uvec_coord.set(0, ++uvec_coord_x);
615 }
616 }
617}
618
619template <typename T>
620inline void colorconvert_yuyv_to_nv12(const SimpleTensor<T> src, const Format format, std::vector<SimpleTensor<T>> &dst)
621{
622 SimpleTensor<T> uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
623 SimpleTensor<T> uvvec_bottom(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
624
625 const int offset = (Format::YUYV422 == format) ? 0 : 1;
626
627 int width = dst[0].shape().x();
628 int height = dst[0].shape().y();
629
630 for(int y = 0; y < height; ++y)
631 {
632 for(int x = 0; x < width; x++)
633 {
634 const Coordinates dst_coord{ x, y };
635 const Coordinates uv_coord{ x, y / 2 };
636
637 const auto *src_pixel = reinterpret_cast<const T *>(src(dst_coord));
638 auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
639 auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
640 auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
641
642 y_pixel[0] = src_pixel[0 + offset];
643
644 if(y % 2 == 0)
645 {
646 uvvec_top_pixel[0] = src_pixel[1 - offset];
647 }
648 else
649 {
650 uvvec_bottom_pixel[0] = src_pixel[1 - offset];
651 }
652 }
653 }
654
655 width = dst[1].shape().x();
656 height = dst[1].shape().y();
657
658 int uv_coord_x = 0;
659 int uv_coord_y = 0;
660
661 for(int y = 0; y < height; ++y)
662 {
663 for(int x = 0; x < width; x++)
664 {
665 const Coordinates dst_coord{ x, y };
666 const Coordinates uv_coord{ uv_coord_x, uv_coord_y };
667
668 auto *uv_pixel = reinterpret_cast<T *>(dst[1](dst_coord));
669 const auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
670 const auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
671
672 uv_pixel[0] = (uvvec_top_pixel[0] + uvvec_bottom_pixel[0]) / 2;
673 uv_pixel[1] = (uvvec_top_pixel[1] + uvvec_bottom_pixel[1]) / 2;
674 uv_coord_x += 2;
675 }
676 uv_coord_x = 0;
677 uv_coord_y++;
678 }
679}
680
681template <typename T>
682inline void colorconvert_yuyv_to_iyuv(const SimpleTensor<T> src, const Format format, std::vector<SimpleTensor<T>> &dst)
683{
684 SimpleTensor<T> uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
685 SimpleTensor<T> uvvec_bottom(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8);
686
687 const int offset = (Format::YUYV422 == format) ? 0 : 1;
688
689 int width = dst[0].shape().x();
690 int height = dst[0].shape().y();
691
692 for(int y = 0; y < height; ++y)
693 {
694 for(int x = 0; x < width; x++)
695 {
696 const Coordinates dst_coord{ x, y };
697 const Coordinates uv_coord{ x, y / 2 };
698
699 const auto *src_pixel = reinterpret_cast<const T *>(src(dst_coord));
700 auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
701 auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
702 auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
703
704 y_pixel[0] = src_pixel[0 + offset];
705
706 if(y % 2 == 0)
707 {
708 uvvec_top_pixel[0] = src_pixel[1 - offset];
709 }
710 else
711 {
712 uvvec_bottom_pixel[0] = src_pixel[1 - offset];
713 }
714 }
715 }
716
717 width = dst[1].shape().x();
718 height = dst[1].shape().y();
719
720 int uv_coord_x = 0;
721 int uv_coord_y = 0;
722
723 for(int y = 0; y < height; ++y)
724 {
725 for(int x = 0; x < width; x++)
726 {
727 const Coordinates dst_coord{ x, y };
728 const Coordinates uv_coord{ uv_coord_x, uv_coord_y };
729
730 auto *u_pixel = reinterpret_cast<T *>(dst[1](dst_coord));
731 auto *v_pixel = reinterpret_cast<T *>(dst[2](dst_coord));
732 const auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord));
733 const auto *uvvec_bottom_pixel = reinterpret_cast<T *>(uvvec_bottom(uv_coord));
734
735 u_pixel[0] = (uvvec_top_pixel[0] + uvvec_bottom_pixel[0]) / 2;
736 v_pixel[0] = (uvvec_top_pixel[1] + uvvec_bottom_pixel[1]) / 2;
737 uv_coord_x += 2;
738 }
739 uv_coord_x = 0;
740 uv_coord_y++;
741 }
742}
743
744template <typename T>
745inline void nv_to_iyuv(const SimpleTensor<T> src, const Format src_format, SimpleTensor<T> &nv1, SimpleTensor<T> &nv2)
746{
747 int width = src.shape().x();
748 int height = src.shape().y();
749
750 const int offset = (Format::NV12 == src_format) ? 1 : 0;
751
752 for(int y = 0; y < height; ++y)
753 {
754 for(int x = 0; x < width; x++)
755 {
756 const Coordinates src_coord{ x, y };
757 const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
758 auto *u_pixel = reinterpret_cast<T *>(nv1(src_coord));
759 auto *v_pixel = reinterpret_cast<T *>(nv2(src_coord));
760
761 u_pixel[0] = src_pixel[1 - offset];
762 v_pixel[0] = src_pixel[0 + offset];
763 }
764 }
765}
766
767template <typename T>
768inline void nv_to_yuv4(const SimpleTensor<T> src, const Format src_format, SimpleTensor<T> &nv1, SimpleTensor<T> &nv2)
769{
770 int width = src.shape().x();
771 int height = src.shape().y();
772
773 const int offset = (Format::NV12 == src_format) ? 1 : 0;
774
775 for(int y = 0; y < height; ++y)
776 {
777 for(int x = 0; x < width; x++)
778 {
779 const Coordinates src_coord{ x, y };
780 Coordinates dst_coord{ x * 2, y * 2 };
781 const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord));
782 auto *u_pixel = reinterpret_cast<T *>(nv1(dst_coord));
783 auto *v_pixel = reinterpret_cast<T *>(nv2(dst_coord));
784
785 u_pixel[0] = src_pixel[1 - offset];
786 u_pixel[1] = src_pixel[1 - offset];
787
788 v_pixel[0] = src_pixel[0 + offset];
789 v_pixel[1] = src_pixel[0 + offset];
790
791 dst_coord.set(1, y * 2 + 1);
792 u_pixel = reinterpret_cast<T *>(nv1(dst_coord));
793 v_pixel = reinterpret_cast<T *>(nv2(dst_coord));
794 u_pixel[0] = src_pixel[1 - offset];
795 u_pixel[1] = src_pixel[1 - offset];
796
797 v_pixel[0] = src_pixel[0 + offset];
798 v_pixel[1] = src_pixel[0 + offset];
799 }
800 }
801}
802
803template <typename T>
804inline void colorconvert_nv_to_iyuv(const std::vector<SimpleTensor<T>> src, const Format src_format, std::vector<SimpleTensor<T>> &dst)
805{
806 int width = dst[0].shape().x();
807 int height = dst[0].shape().y();
808
809 for(int y = 0; y < height; ++y)
810 {
811 for(int x = 0; x < width; ++x)
812 {
813 const Coordinates dst_coord{ x, y };
814
815 const auto *src_pixel = reinterpret_cast<const T *>(src[0](dst_coord));
816 auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
817
818 y_pixel[0] = src_pixel[0];
819 }
820 }
821
822 nv_to_iyuv(src[1], src_format, dst[1], dst[2]);
823}
824
825template <typename T>
826inline void colorconvert_nv_to_yuv4(const std::vector<SimpleTensor<T>> src, const Format src_format, std::vector<SimpleTensor<T>> &dst)
827{
828 int width = dst[0].shape().x();
829 int height = dst[0].shape().y();
830
831 for(int y = 0; y < height; ++y)
832 {
833 for(int x = 0; x < width; ++x)
834 {
835 const Coordinates dst_coord{ x, y };
836
837 const auto *src_pixel = reinterpret_cast<const T *>(src[0](dst_coord));
838 auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord));
839
840 y_pixel[0] = src_pixel[0];
841 }
842 }
843
844 nv_to_yuv4(src[1], src_format, dst[1], dst[2]);
845}
846
Sanghoon Lee1fad27a2018-04-05 10:57:57 +0100847} // namespace detail
848} // color_convert_helper
849} // namespace test
850} // namespace arm_compute
851#endif /*__ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H__ */