From dec32a9edd4b3c6dc55c60d7436e79af6be58c3d Mon Sep 17 00:00:00 2001 From: Sanghoon Lee Date: Fri, 29 Jun 2018 10:52:57 +0100 Subject: COMPMID-566: Implement reference and CL/NEON validation for ColorConvert (part 2) Change-Id: I4371c4b6403f55ea7d7baf39df91a45f45b21d5a Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/137975 Tested-by: Jenkins Reviewed-by: Anthony Barbier --- tests/validation/reference/ColorConvertHelper.h | 553 +++++++++++++++++++++++- 1 file changed, 545 insertions(+), 8 deletions(-) (limited to 'tests/validation/reference/ColorConvertHelper.h') diff --git a/tests/validation/reference/ColorConvertHelper.h b/tests/validation/reference/ColorConvertHelper.h index b4255a0f20..ee446683d6 100644 --- a/tests/validation/reference/ColorConvertHelper.h +++ b/tests/validation/reference/ColorConvertHelper.h @@ -39,6 +39,87 @@ constexpr float green_coef_bt709 = -0.1873f; constexpr float green_coef2_bt709 = -0.4681f; constexpr float blue_coef_bt709 = 1.8556f; +constexpr float rgb2yuv_bt709_kr = 0.2126f; +constexpr float rgb2yuv_bt709_kb = 0.0722f; +// K_g = 1 - K_r - K_b +constexpr float rgb2yuv_bt709_kg = 0.7152f; +// C_u = 1 / (2 * (1 - K_b)) +constexpr float rgb2yuv_bt709_cu = 0.5389f; +// C_v = 1 / (2 * (1 - K_r)) +constexpr float rgb2yuv_bt709_cv = 0.6350f; + +template +inline void store_rgb_from_src(const SimpleTensor src, SimpleTensor &rvec, SimpleTensor &gvec, SimpleTensor &bvec) +{ + int width = src.shape().x(); + int height = src.shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; ++x) + { + const Coordinates src_coord{ x, y }; + const Coordinates vec_coord{ x, y }; + + const auto *src_pixel = reinterpret_cast(src(src_coord)); + auto *rvec_pixel = reinterpret_cast(rvec(vec_coord)); + auto *gvec_pixel = reinterpret_cast(gvec(vec_coord)); + auto *bvec_pixel = reinterpret_cast(bvec(vec_coord)); + + rvec_pixel[0] = src_pixel[0]; + gvec_pixel[0] = src_pixel[1]; + bvec_pixel[0] = src_pixel[2]; + } + } +} + +template +inline void rgb_to_yuv_calculation(const SimpleTensor rvec, const SimpleTensor gvec, const SimpleTensor bvec, SimpleTensor &yvec, SimpleTensor &uvec_top, SimpleTensor &uvec_bottom, + SimpleTensor &vvec_top, SimpleTensor &vvec_bottom) +{ + int width = rvec.shape().x(); + int height = rvec.shape().y(); + + int uvec_coord_x = 0; + int uvec_coord_y = 0; + Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y }; + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x += 2) + { + Coordinates coord{ x, y }; + auto *yvec_pixel = reinterpret_cast(yvec(coord)); + auto *uvec_top_pixel = reinterpret_cast(uvec_top(uvec_coord)); + auto *uvec_bottom_pixel = reinterpret_cast(uvec_bottom(uvec_coord)); + auto *vvec_top_pixel = reinterpret_cast(vvec_top(uvec_coord)); + auto *vvec_bottom_pixel = reinterpret_cast(vvec_bottom(uvec_coord)); + + T border_value(0); + int rvec_val = validation::tensor_elem_at(rvec, coord, BorderMode::CONSTANT, border_value); + int gvec_val = validation::tensor_elem_at(gvec, coord, BorderMode::CONSTANT, border_value); + int bvec_val = validation::tensor_elem_at(bvec, coord, BorderMode::CONSTANT, border_value); + float result = rvec_val * rgb2yuv_bt709_kr + gvec_val * rgb2yuv_bt709_kg + bvec_val * rgb2yuv_bt709_kb; + + yvec_pixel[0] = result; + uvec_top_pixel[0] = (bvec_val - result) * rgb2yuv_bt709_cu + 128.f; + vvec_top_pixel[0] = (rvec_val - result) * rgb2yuv_bt709_cv + 128.f; + + coord.set(0, x + 1); + rvec_val = validation::tensor_elem_at(rvec, coord, BorderMode::CONSTANT, border_value); + gvec_val = validation::tensor_elem_at(gvec, coord, BorderMode::CONSTANT, border_value); + bvec_val = validation::tensor_elem_at(bvec, coord, BorderMode::CONSTANT, border_value); + result = rvec_val * rgb2yuv_bt709_kr + gvec_val * rgb2yuv_bt709_kg + bvec_val * rgb2yuv_bt709_kb; + + yvec_pixel[1] = result; + uvec_bottom_pixel[0] = (bvec_val - result) * rgb2yuv_bt709_cu + 128.f; + vvec_bottom_pixel[0] = (rvec_val - result) * rgb2yuv_bt709_cv + 128.f; + + uvec_coord.set(0, ++uvec_coord_x); + } + } +} + template inline void yuyv_to_rgb_calculation(const SimpleTensor yvec, const SimpleTensor vvec, const SimpleTensor yyvec, const SimpleTensor uvec, SimpleTensor &dst) { @@ -59,9 +140,9 @@ inline void yuyv_to_rgb_calculation(const SimpleTensor yvec, const SimpleTens const int vvec_val = validation::tensor_elem_at(vvec, { x_coord, y }, BorderMode::CONSTANT, border_value); const int yyvec_val = validation::tensor_elem_at(yyvec, { x_coord, y }, BorderMode::CONSTANT, border_value); const int uvec_val = validation::tensor_elem_at(uvec, { x_coord, y }, BorderMode::CONSTANT, border_value); - const float red = (vvec_val - 128) * red_coef_bt709; - const float green = (uvec_val - 128) * green_coef_bt709 + (vvec_val - 128) * green_coef2_bt709; - const float blue = (uvec_val - 128) * blue_coef_bt709; + const float red = (vvec_val - 128.f) * red_coef_bt709; + const float green = (uvec_val - 128.f) * green_coef_bt709 + (vvec_val - 128.f) * green_coef2_bt709; + const float blue = (uvec_val - 128.f) * blue_coef_bt709; for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx) { @@ -261,16 +342,17 @@ inline void colorconvert_iyuv_to_rgb(const TensorShape &shape, const std::vector for(int x = 0; x < uvec_width; ++x) { const Coordinates src_coord{ x, y / 2 }; - const auto *src_pixel = reinterpret_cast(tensor_planes[1](src_coord)); + const auto *u_pixel = reinterpret_cast(tensor_planes[1](src_coord)); + const auto *v_pixel = reinterpret_cast(tensor_planes[2](src_coord)); auto *uvec_pixel_top = reinterpret_cast(uvec(top_elem_coord)); auto *vvec_pixel_top = reinterpret_cast(vvec(top_elem_coord)); auto *uvec_pixel_bottom = reinterpret_cast(uvec(bottom_elem_coord)); auto *vvec_pixel_bottom = reinterpret_cast(vvec(bottom_elem_coord)); - uvec_pixel_top[x] = src_pixel[0]; - vvec_pixel_top[x] = src_pixel[0]; - uvec_pixel_bottom[x] = src_pixel[0]; - vvec_pixel_bottom[x] = src_pixel[0]; + uvec_pixel_top[x] = u_pixel[0]; + vvec_pixel_top[x] = v_pixel[0]; + uvec_pixel_bottom[x] = u_pixel[0]; + vvec_pixel_bottom[x] = v_pixel[0]; } top_elem_coord.set(1, y + 2); bottom_elem_coord.set(1, top_elem_coord.y() + 1); @@ -335,6 +417,461 @@ inline void colorconvert_nv12_to_rgb(const TensorShape &shape, const Format form yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst); } +template +inline void colorconvert_rgb_to_nv12(const SimpleTensor src, std::vector> &dst) +{ + SimpleTensor rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + + int vec_shape_x = src.shape().x() * src.shape().y(); + + SimpleTensor uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + + store_rgb_from_src(src, rvec, gvec, bvec); + rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom); + + SimpleTensor utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8); + SimpleTensor vtmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8); + + int utmp_width = utmp.shape().x(); + int utmp_height = utmp.shape().y(); + + int uvec_coord_x = 0; + int uvec_coord_y = 0; + Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y }; + for(int y = 0; y < utmp_height; y++) + { + for(int x = 0; x < utmp_width; x++) + { + Coordinates coord{ x, y }; + auto *utmp_pixel = reinterpret_cast(utmp(coord)); + auto *vtmp_pixel = reinterpret_cast(vtmp(coord)); + + T border_value(0); + int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value); + int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value); + int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value); + int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value); + + utmp_pixel[0] = std::ceil(float(uvec_top_val + uvec_bottom_val) / 2); + vtmp_pixel[0] = std::ceil(float(vvec_top_val + vvec_bottom_val) / 2); + + uvec_coord.set(0, ++uvec_coord_x); + } + } + + int second_plane_x = dst[1].shape().x(); + int second_plane_y = dst[1].shape().y(); + + int utmp_coord_x = 0; + int utmp_coord_y = 0; + + for(int y = 0; y < second_plane_y; y++) + { + for(int x = 0; x < second_plane_x; x++) + { + Coordinates coord{ x, y }; + Coordinates utmp_top_coord{ utmp_coord_x, utmp_coord_y }; + Coordinates utmp_bottom_coord{ utmp_coord_x, utmp_coord_y + 1 }; + + auto *dst_pixel = reinterpret_cast(dst[1](coord)); + + T border_value(0); + int utmp_top_val = validation::tensor_elem_at(utmp, utmp_top_coord, BorderMode::CONSTANT, border_value); + int utmp_bottom_val = validation::tensor_elem_at(utmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value); + + int result = (utmp_top_val + utmp_bottom_val) / 2; + dst_pixel[0] = result; + + int vtmp_top_val = validation::tensor_elem_at(vtmp, utmp_top_coord, BorderMode::CONSTANT, border_value); + int vtmp_bottom_val = validation::tensor_elem_at(vtmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value); + + result = (vtmp_top_val + vtmp_bottom_val) / 2; + dst_pixel[1] = result; + + utmp_coord_x++; + + if(utmp_coord_x >= utmp_width) + { + utmp_coord_x = 0; + utmp_coord_y += 2; + } + } + } +} + +template +inline void colorconvert_rgb_to_iyuv(const SimpleTensor src, std::vector> &dst) +{ + SimpleTensor rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + + int vec_shape_x = src.shape().x() * src.shape().y(); + + SimpleTensor uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + + store_rgb_from_src(src, rvec, gvec, bvec); + rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom); + + SimpleTensor utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8); + SimpleTensor vtmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8); + int utmp_width = utmp.shape().x(); + int utmp_height = utmp.shape().y(); + + int uvec_coord_x = 0; + int uvec_coord_y = 0; + Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y }; + for(int y = 0; y < utmp_height; y++) + { + for(int x = 0; x < utmp_width; x++) + { + Coordinates coord{ x, y }; + auto *utmp_pixel = reinterpret_cast(utmp(coord)); + auto *vtmp_pixel = reinterpret_cast(vtmp(coord)); + + T border_value(0); + int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value); + int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value); + int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value); + int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value); + + utmp_pixel[0] = std::ceil(float(uvec_top_val + uvec_bottom_val) / 2); + vtmp_pixel[0] = std::ceil(float(vvec_top_val + vvec_bottom_val) / 2); + + uvec_coord.set(0, ++uvec_coord_x); + } + } + + int second_plane_x = dst[1].shape().x(); + int second_plane_y = dst[1].shape().y(); + + int utmp_coord_x = 0; + int utmp_coord_y = 0; + + for(int y = 0; y < second_plane_y; y++) + { + for(int x = 0; x < second_plane_x; x++) + { + Coordinates coord{ x, y }; + Coordinates utmp_top_coord{ utmp_coord_x, utmp_coord_y }; + Coordinates utmp_bottom_coord{ utmp_coord_x, utmp_coord_y + 1 }; + + auto *u_pixel = reinterpret_cast(dst[1](coord)); + auto *v_pixel = reinterpret_cast(dst[2](coord)); + + T border_value(0); + int utmp_top_val = validation::tensor_elem_at(utmp, utmp_top_coord, BorderMode::CONSTANT, border_value); + int utmp_bottom_val = validation::tensor_elem_at(utmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value); + + int result = (utmp_top_val + utmp_bottom_val) / 2; + u_pixel[0] = result; + + int vtmp_top_val = validation::tensor_elem_at(vtmp, utmp_top_coord, BorderMode::CONSTANT, border_value); + int vtmp_bottom_val = validation::tensor_elem_at(vtmp, utmp_bottom_coord, BorderMode::CONSTANT, border_value); + + result = (vtmp_top_val + vtmp_bottom_val) / 2; + v_pixel[0] = result; + + utmp_coord_x++; + + if(utmp_coord_x >= utmp_width) + { + utmp_coord_x = 0; + utmp_coord_y += 2; + } + } + } +} + +template +inline void colorconvert_rgb_to_yuv4(const SimpleTensor src, std::vector> &dst) +{ + SimpleTensor rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + + int vec_shape_x = src.shape().x() * src.shape().y(); + + SimpleTensor uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor vvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + + int width = src.shape().x(); + int height = src.shape().y(); + + store_rgb_from_src(src, rvec, gvec, bvec); + + rgb_to_yuv_calculation(rvec, gvec, bvec, dst[0], uvec_top, uvec_bottom, vvec_top, vvec_bottom); + + int uvec_coord_x = 0; + int uvec_coord_y = 0; + Coordinates uvec_coord{ uvec_coord_x, uvec_coord_y }; + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x += 2) + { + Coordinates coord{ x, y }; + auto *plane_1_pixel = reinterpret_cast(dst[1](coord)); + auto *plane_2_pixel = reinterpret_cast(dst[2](coord)); + + T border_value(0); + int uvec_top_val = validation::tensor_elem_at(uvec_top, uvec_coord, BorderMode::CONSTANT, border_value); + int uvec_bottom_val = validation::tensor_elem_at(uvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value); + + plane_1_pixel[0] = uvec_top_val; + plane_1_pixel[1] = uvec_bottom_val; + + int vvec_top_val = validation::tensor_elem_at(vvec_top, uvec_coord, BorderMode::CONSTANT, border_value); + int vvec_bottom_val = validation::tensor_elem_at(vvec_bottom, uvec_coord, BorderMode::CONSTANT, border_value); + + plane_2_pixel[0] = vvec_top_val; + plane_2_pixel[1] = vvec_bottom_val; + + uvec_coord.set(0, ++uvec_coord_x); + } + } +} + +template +inline void colorconvert_yuyv_to_nv12(const SimpleTensor src, const Format format, std::vector> &dst) +{ + SimpleTensor uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8); + SimpleTensor uvvec_bottom(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8); + + const int offset = (Format::YUYV422 == format) ? 0 : 1; + + int width = dst[0].shape().x(); + int height = dst[0].shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x++) + { + const Coordinates dst_coord{ x, y }; + const Coordinates uv_coord{ x, y / 2 }; + + const auto *src_pixel = reinterpret_cast(src(dst_coord)); + auto *y_pixel = reinterpret_cast(dst[0](dst_coord)); + auto *uvvec_top_pixel = reinterpret_cast(uvvec_top(uv_coord)); + auto *uvvec_bottom_pixel = reinterpret_cast(uvvec_bottom(uv_coord)); + + y_pixel[0] = src_pixel[0 + offset]; + + if(y % 2 == 0) + { + uvvec_top_pixel[0] = src_pixel[1 - offset]; + } + else + { + uvvec_bottom_pixel[0] = src_pixel[1 - offset]; + } + } + } + + width = dst[1].shape().x(); + height = dst[1].shape().y(); + + int uv_coord_x = 0; + int uv_coord_y = 0; + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x++) + { + const Coordinates dst_coord{ x, y }; + const Coordinates uv_coord{ uv_coord_x, uv_coord_y }; + + auto *uv_pixel = reinterpret_cast(dst[1](dst_coord)); + const auto *uvvec_top_pixel = reinterpret_cast(uvvec_top(uv_coord)); + const auto *uvvec_bottom_pixel = reinterpret_cast(uvvec_bottom(uv_coord)); + + uv_pixel[0] = (uvvec_top_pixel[0] + uvvec_bottom_pixel[0]) / 2; + uv_pixel[1] = (uvvec_top_pixel[1] + uvvec_bottom_pixel[1]) / 2; + uv_coord_x += 2; + } + uv_coord_x = 0; + uv_coord_y++; + } +} + +template +inline void colorconvert_yuyv_to_iyuv(const SimpleTensor src, const Format format, std::vector> &dst) +{ + SimpleTensor uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8); + SimpleTensor uvvec_bottom(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8); + + const int offset = (Format::YUYV422 == format) ? 0 : 1; + + int width = dst[0].shape().x(); + int height = dst[0].shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x++) + { + const Coordinates dst_coord{ x, y }; + const Coordinates uv_coord{ x, y / 2 }; + + const auto *src_pixel = reinterpret_cast(src(dst_coord)); + auto *y_pixel = reinterpret_cast(dst[0](dst_coord)); + auto *uvvec_top_pixel = reinterpret_cast(uvvec_top(uv_coord)); + auto *uvvec_bottom_pixel = reinterpret_cast(uvvec_bottom(uv_coord)); + + y_pixel[0] = src_pixel[0 + offset]; + + if(y % 2 == 0) + { + uvvec_top_pixel[0] = src_pixel[1 - offset]; + } + else + { + uvvec_bottom_pixel[0] = src_pixel[1 - offset]; + } + } + } + + width = dst[1].shape().x(); + height = dst[1].shape().y(); + + int uv_coord_x = 0; + int uv_coord_y = 0; + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x++) + { + const Coordinates dst_coord{ x, y }; + const Coordinates uv_coord{ uv_coord_x, uv_coord_y }; + + auto *u_pixel = reinterpret_cast(dst[1](dst_coord)); + auto *v_pixel = reinterpret_cast(dst[2](dst_coord)); + const auto *uvvec_top_pixel = reinterpret_cast(uvvec_top(uv_coord)); + const auto *uvvec_bottom_pixel = reinterpret_cast(uvvec_bottom(uv_coord)); + + u_pixel[0] = (uvvec_top_pixel[0] + uvvec_bottom_pixel[0]) / 2; + v_pixel[0] = (uvvec_top_pixel[1] + uvvec_bottom_pixel[1]) / 2; + uv_coord_x += 2; + } + uv_coord_x = 0; + uv_coord_y++; + } +} + +template +inline void nv_to_iyuv(const SimpleTensor src, const Format src_format, SimpleTensor &nv1, SimpleTensor &nv2) +{ + int width = src.shape().x(); + int height = src.shape().y(); + + const int offset = (Format::NV12 == src_format) ? 1 : 0; + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x++) + { + const Coordinates src_coord{ x, y }; + const auto *src_pixel = reinterpret_cast(src(src_coord)); + auto *u_pixel = reinterpret_cast(nv1(src_coord)); + auto *v_pixel = reinterpret_cast(nv2(src_coord)); + + u_pixel[0] = src_pixel[1 - offset]; + v_pixel[0] = src_pixel[0 + offset]; + } + } +} + +template +inline void nv_to_yuv4(const SimpleTensor src, const Format src_format, SimpleTensor &nv1, SimpleTensor &nv2) +{ + int width = src.shape().x(); + int height = src.shape().y(); + + const int offset = (Format::NV12 == src_format) ? 1 : 0; + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; x++) + { + const Coordinates src_coord{ x, y }; + Coordinates dst_coord{ x * 2, y * 2 }; + const auto *src_pixel = reinterpret_cast(src(src_coord)); + auto *u_pixel = reinterpret_cast(nv1(dst_coord)); + auto *v_pixel = reinterpret_cast(nv2(dst_coord)); + + u_pixel[0] = src_pixel[1 - offset]; + u_pixel[1] = src_pixel[1 - offset]; + + v_pixel[0] = src_pixel[0 + offset]; + v_pixel[1] = src_pixel[0 + offset]; + + dst_coord.set(1, y * 2 + 1); + u_pixel = reinterpret_cast(nv1(dst_coord)); + v_pixel = reinterpret_cast(nv2(dst_coord)); + u_pixel[0] = src_pixel[1 - offset]; + u_pixel[1] = src_pixel[1 - offset]; + + v_pixel[0] = src_pixel[0 + offset]; + v_pixel[1] = src_pixel[0 + offset]; + } + } +} + +template +inline void colorconvert_nv_to_iyuv(const std::vector> src, const Format src_format, std::vector> &dst) +{ + int width = dst[0].shape().x(); + int height = dst[0].shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; ++x) + { + const Coordinates dst_coord{ x, y }; + + const auto *src_pixel = reinterpret_cast(src[0](dst_coord)); + auto *y_pixel = reinterpret_cast(dst[0](dst_coord)); + + y_pixel[0] = src_pixel[0]; + } + } + + nv_to_iyuv(src[1], src_format, dst[1], dst[2]); +} + +template +inline void colorconvert_nv_to_yuv4(const std::vector> src, const Format src_format, std::vector> &dst) +{ + int width = dst[0].shape().x(); + int height = dst[0].shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; ++x) + { + const Coordinates dst_coord{ x, y }; + + const auto *src_pixel = reinterpret_cast(src[0](dst_coord)); + auto *y_pixel = reinterpret_cast(dst[0](dst_coord)); + + y_pixel[0] = src_pixel[0]; + } + } + + nv_to_yuv4(src[1], src_format, dst[1], dst[2]); +} + } // namespace detail } // color_convert_helper } // namespace test -- cgit v1.2.1