diff options
author | Sanghoon Lee <sanghoon.lee@arm.com> | 2018-06-29 10:52:57 +0100 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-11-02 16:54:10 +0000 |
commit | dec32a9edd4b3c6dc55c60d7436e79af6be58c3d (patch) | |
tree | 0aafd0e56a4482f7a8215a1c9f9592552a27c5c4 | |
parent | 149fdf3cad6b42ed302ebe2b0d614a36b9b4d81c (diff) | |
download | ComputeLibrary-dec32a9edd4b3c6dc55c60d7436e79af6be58c3d.tar.gz |
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 <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
-rw-r--r-- | tests/validation/CL/ColorConvert.cpp | 182 | ||||
-rw-r--r-- | tests/validation/NEON/ColorConvert.cpp | 181 | ||||
-rw-r--r-- | tests/validation/fixtures/ColorConvertFixture.h | 81 | ||||
-rw-r--r-- | tests/validation/reference/ColorConvert.cpp | 102 | ||||
-rw-r--r-- | tests/validation/reference/ColorConvert.h | 2 | ||||
-rw-r--r-- | tests/validation/reference/ColorConvertHelper.h | 553 |
6 files changed, 1013 insertions, 88 deletions
diff --git a/tests/validation/CL/ColorConvert.cpp b/tests/validation/CL/ColorConvert.cpp index 6d04511629..c99fa3cee1 100644 --- a/tests/validation/CL/ColorConvert.cpp +++ b/tests/validation/CL/ColorConvert.cpp @@ -40,6 +40,8 @@ namespace validation { namespace { +constexpr AbsoluteTolerance<uint8_t> tolerance_nv(2); + // Input data sets const auto ColorConvertRGBADataset = combine(framework::dataset::make("FormatType", { Format::RGBA8888 }), framework::dataset::make("FormatType", { Format::RGB888 })); @@ -52,30 +54,68 @@ const auto ColorConvertYUVPlanarDataset = combine(framework::dataset::make("Form const auto ColorConvertRGBDataset = combine(framework::dataset::make("FormatType", { Format::RGB888 }), framework::dataset::make("FormatType", { Format::RGBA8888 })); +const auto ColorConvertNVDataset = combine(framework::dataset::make("FormatType", { Format::RGB888, Format::RGBA8888 }), + framework::dataset::make("FormatType", { Format::NV12, Format::IYUV, Format::YUV444 })); + +const auto ColorConvertYUYVtoNVDataset = combine(framework::dataset::make("FormatType", { Format::UYVY422, Format::YUYV422 }), + framework::dataset::make("FormatType", { Format::NV12, Format::IYUV })); + +const auto ColorConvertNVtoYUVDataset = combine(framework::dataset::make("FormatType", { Format::NV12, Format::NV21 }), + framework::dataset::make("FormatType", { Format::IYUV, Format::YUV444 })); + inline void validate_configuration(const TensorShape &shape, Format src_format, Format dst_format) { const unsigned int src_num_planes = num_planes_from_format(src_format); + const unsigned int dst_num_planes = num_planes_from_format(dst_format); - const TensorShape dst_shape = adjust_odd_shape(shape, src_format); + TensorShape input = adjust_odd_shape(shape, src_format); + input = adjust_odd_shape(input, src_format); // Create tensors - CLMultiImage ref_src = create_multi_image<CLMultiImage>(shape, src_format); - CLTensor dst = create_tensor<CLTensor>(dst_shape, dst_format); + CLMultiImage ref_src = create_multi_image<CLMultiImage>(input, src_format); + CLMultiImage ref_dst = create_multi_image<CLMultiImage>(input, dst_format); // Create and Configure function CLColorConvert color_convert; if(1U == src_num_planes) { - const CLTensor *plane_src = ref_src.cl_plane(0); + const CLTensor *src_plane = ref_src.cl_plane(0); - color_convert.configure(plane_src, &dst); - const ValidRegion dst_valid_region = shape_to_valid_region(dst_shape); - validate(dst.info()->valid_region(), dst_valid_region); + if(1U == dst_num_planes) + { + CLTensor *dst_plane = ref_dst.cl_plane(0); + color_convert.configure(src_plane, dst_plane); + } + else + { + color_convert.configure(src_plane, &ref_dst); + } } else { - color_convert.configure(&ref_src, &dst); + if(1U == dst_num_planes) + { + CLTensor *dst_plane = ref_dst.cl_plane(0); + color_convert.configure(&ref_src, dst_plane); + } + else + { + color_convert.configure(&ref_src, &ref_dst); + } + } + + for(unsigned int plane_idx = 0; plane_idx < src_num_planes; ++plane_idx) + { + const CLTensor *src_plane = ref_src.cl_plane(plane_idx); + + ARM_COMPUTE_EXPECT(src_plane->info()->is_resizable(), framework::LogLevel::ERRORS); + } + for(unsigned int plane_idx = 0; plane_idx < dst_num_planes; ++plane_idx) + { + const CLTensor *dst_plane = ref_dst.cl_plane(plane_idx); + + ARM_COMPUTE_EXPECT(dst_plane->info()->is_resizable(), framework::LogLevel::ERRORS); } } } // namespace @@ -83,6 +123,9 @@ inline void validate_configuration(const TensorShape &shape, Format src_format, TEST_SUITE(CL) TEST_SUITE(ColorConvert) +template <typename T> +using CLColorConvertFixture = ColorConvertValidationFixture<CLMultiImage, CLTensor, CLAccessor, CLColorConvert, T>; + TEST_SUITE(Configuration) DATA_TEST_CASE(RGBA, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertRGBADataset), shape, src_format, dst_format) @@ -107,34 +150,63 @@ DATA_TEST_CASE(RGB, framework::DatasetMode::ALL, combine(concat(datasets::Small2 { validate_configuration(shape, src_format, dst_format); } -TEST_SUITE_END() -template <typename T> -using CLColorConvertFixture = ColorConvertValidationFixture<CLMultiImage, CLTensor, CLAccessor, CLColorConvert, T>; +DATA_TEST_CASE(NV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertNVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(YUVtoNV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertYUYVtoNVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(NVtoYUV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertNVtoYUVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} +TEST_SUITE_END() TEST_SUITE(RGBA) FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBADataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBADataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } + TEST_SUITE_END() TEST_SUITE(YUV) FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUVDataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVDataset)) { - validate(CLAccessor(_target), _reference); + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } TEST_SUITE_END() @@ -142,12 +214,18 @@ TEST_SUITE(YUVPlanar) FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUVPlanarDataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVPlanarDataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } TEST_SUITE_END() @@ -155,14 +233,80 @@ TEST_SUITE(RGB) FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBDataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBDataset)) { // Validate output - validate(CLAccessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } +} +TEST_SUITE_END() + +TEST_SUITE(NV) +FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx], tolerance_nv); + } +} +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx], tolerance_nv); + } +} +TEST_SUITE_END() + +TEST_SUITE(YUYVtoNV) +FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUYVtoNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } +} +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUYVtoNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } +} + +TEST_SUITE_END() + +TEST_SUITE(NVtoYUV) +FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertNVtoYUVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } } +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertNVtoYUVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(CLAccessor(*_target.cl_plane(plane_idx)), _reference[plane_idx]); + } +} + TEST_SUITE_END() + TEST_SUITE_END() TEST_SUITE_END() } // namespace validation diff --git a/tests/validation/NEON/ColorConvert.cpp b/tests/validation/NEON/ColorConvert.cpp index ab6ec5b725..ec2f1b8edc 100644 --- a/tests/validation/NEON/ColorConvert.cpp +++ b/tests/validation/NEON/ColorConvert.cpp @@ -40,6 +40,8 @@ namespace validation { namespace { +constexpr AbsoluteTolerance<uint8_t> tolerance_nv(2); + // Input data sets const auto ColorConvertRGBADataset = combine(framework::dataset::make("FormatType", { Format::RGBA8888 }), framework::dataset::make("FormatType", { Format::RGB888 })); @@ -52,30 +54,68 @@ const auto ColorConvertYUVPlanarDataset = combine(framework::dataset::make("Form const auto ColorConvertRGBDataset = combine(framework::dataset::make("FormatType", { Format::RGB888 }), framework::dataset::make("FormatType", { Format::RGBA8888 })); +const auto ColorConvertNVDataset = combine(framework::dataset::make("FormatType", { Format::RGB888, Format::RGBA8888 }), + framework::dataset::make("FormatType", { Format::NV12, Format::IYUV, Format::YUV444 })); + +const auto ColorConvertYUYVtoNVDataset = combine(framework::dataset::make("FormatType", { Format::UYVY422, Format::YUYV422 }), + framework::dataset::make("FormatType", { Format::NV12, Format::IYUV })); + +const auto ColorConvertNVtoYUVDataset = combine(framework::dataset::make("FormatType", { Format::NV12, Format::NV21 }), + framework::dataset::make("FormatType", { Format::IYUV, Format::YUV444 })); + inline void validate_configuration(const TensorShape &shape, Format src_format, Format dst_format) { const unsigned int src_num_planes = num_planes_from_format(src_format); + const unsigned int dst_num_planes = num_planes_from_format(dst_format); - const TensorShape dst_shape = adjust_odd_shape(shape, src_format); + TensorShape input = adjust_odd_shape(shape, src_format); + input = adjust_odd_shape(input, dst_format); // Create tensors - MultiImage ref_src = create_multi_image<MultiImage>(shape, src_format); - Tensor dst = create_tensor<Tensor>(dst_shape, dst_format); + MultiImage ref_src = create_multi_image<MultiImage>(input, src_format); + MultiImage ref_dst = create_multi_image<MultiImage>(input, dst_format); // Create and Configure function NEColorConvert color_convert; if(1U == src_num_planes) { - const Tensor *plane_src = ref_src.plane(0); + const Tensor *src_plane = ref_src.plane(0); - color_convert.configure(plane_src, &dst); - const ValidRegion dst_valid_region = shape_to_valid_region(dst_shape); - validate(dst.info()->valid_region(), dst_valid_region); + if(1U == dst_num_planes) + { + Tensor *dst_plane = ref_dst.plane(0); + color_convert.configure(src_plane, dst_plane); + } + else + { + color_convert.configure(src_plane, &ref_dst); + } } else { - color_convert.configure(&ref_src, &dst); + if(1U == dst_num_planes) + { + Tensor *dst_plane = ref_dst.plane(0); + color_convert.configure(&ref_src, dst_plane); + } + else + { + color_convert.configure(&ref_src, &ref_dst); + } + } + + for(unsigned int plane_idx = 0; plane_idx < src_num_planes; ++plane_idx) + { + const Tensor *src_plane = ref_src.plane(plane_idx); + + ARM_COMPUTE_EXPECT(src_plane->info()->is_resizable(), framework::LogLevel::ERRORS); + } + for(unsigned int plane_idx = 0; plane_idx < dst_num_planes; ++plane_idx) + { + const Tensor *dst_plane = ref_dst.plane(plane_idx); + + ARM_COMPUTE_EXPECT(dst_plane->info()->is_resizable(), framework::LogLevel::ERRORS); } } } // namespace @@ -83,6 +123,9 @@ inline void validate_configuration(const TensorShape &shape, Format src_format, TEST_SUITE(NEON) TEST_SUITE(ColorConvert) +template <typename T> +using NEColorConvertFixture = ColorConvertValidationFixture<MultiImage, Tensor, Accessor, NEColorConvert, T>; + TEST_SUITE(Configuration) DATA_TEST_CASE(RGBA, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertRGBADataset), shape, src_format, dst_format) @@ -107,35 +150,62 @@ DATA_TEST_CASE(RGB, framework::DatasetMode::ALL, combine(concat(datasets::Small2 { validate_configuration(shape, src_format, dst_format); } -TEST_SUITE_END() -template <typename T> -using NEColorConvertFixture = ColorConvertValidationFixture<MultiImage, Tensor, Accessor, NEColorConvert, T>; +DATA_TEST_CASE(NV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertNVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(YUVtoNV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertYUYVtoNVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(NVtoYUV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertNVtoYUVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} +TEST_SUITE_END() TEST_SUITE(RGBA) FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBADataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } + FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBADataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } - TEST_SUITE_END() TEST_SUITE(YUV) FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUVDataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVDataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } TEST_SUITE_END() @@ -144,12 +214,18 @@ TEST_SUITE(YUVPlanar) FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUVPlanarDataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVPlanarDataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } TEST_SUITE_END() @@ -157,12 +233,77 @@ TEST_SUITE(RGB) FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBDataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBDataset)) { // Validate output - validate(Accessor(_target), _reference); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } +} +TEST_SUITE_END() + +TEST_SUITE(NV) +FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx], tolerance_nv); + } +} + +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx], tolerance_nv); + } +} +TEST_SUITE_END() + +TEST_SUITE(YUVtoNV) +FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUYVtoNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } +} + +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUYVtoNVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } +} +TEST_SUITE_END() + +TEST_SUITE(NVtoYUV) +FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertNVtoYUVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } +} +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertNVtoYUVDataset)) +{ + // Validate output + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + validate(Accessor(*_target.plane(plane_idx)), _reference[plane_idx]); + } } TEST_SUITE_END() diff --git a/tests/validation/fixtures/ColorConvertFixture.h b/tests/validation/fixtures/ColorConvertFixture.h index bd00d4f724..52a9de87b0 100644 --- a/tests/validation/fixtures/ColorConvertFixture.h +++ b/tests/validation/fixtures/ColorConvertFixture.h @@ -51,6 +51,7 @@ public: void setup(TensorShape shape, Format src_format, Format dst_format) { shape = adjust_odd_shape(shape, src_format); + shape = adjust_odd_shape(shape, dst_format); _target = compute_target(shape, src_format, dst_format); _reference = compute_reference(shape, src_format, dst_format); @@ -60,13 +61,11 @@ protected: template <typename U> void fill(U &&tensor, int i) { - library->fill_tensor_uniform(tensor, 1); + library->fill_tensor_uniform(tensor, i); } std::vector<SimpleTensor<T>> create_tensor_planes_reference(const TensorShape &shape, Format format) { - TensorShape input = adjust_odd_shape(shape, format); - std::vector<SimpleTensor<T>> tensor_planes; switch(format) @@ -76,7 +75,7 @@ protected: case Format::YUYV422: case Format::UYVY422: { - tensor_planes.emplace_back(input, format); + tensor_planes.emplace_back(shape, format); break; } case Format::NV12: @@ -84,7 +83,7 @@ protected: { const TensorShape shape_uv88 = calculate_subsampled_shape(shape, Format::UV88); - tensor_planes.emplace_back(input, Format::U8); + tensor_planes.emplace_back(shape, Format::U8); tensor_planes.emplace_back(shape_uv88, Format::UV88); break; } @@ -92,16 +91,16 @@ protected: { const TensorShape shape_sub2 = calculate_subsampled_shape(shape, Format::IYUV); - tensor_planes.emplace_back(input, Format::U8); + tensor_planes.emplace_back(shape, Format::U8); tensor_planes.emplace_back(shape_sub2, Format::U8); tensor_planes.emplace_back(shape_sub2, Format::U8); break; } case Format::YUV444: { - tensor_planes.emplace_back(input, Format::U8); - tensor_planes.emplace_back(input, Format::U8); - tensor_planes.emplace_back(input, Format::U8); + tensor_planes.emplace_back(shape, Format::U8); + tensor_planes.emplace_back(shape, Format::U8); + tensor_planes.emplace_back(shape, Format::U8); break; } default: @@ -112,51 +111,76 @@ protected: return tensor_planes; } - TensorType compute_target(const TensorShape &shape, Format src_format, Format dst_format) + MultiImageType compute_target(const TensorShape &shape, Format src_format, Format dst_format) { - const unsigned int num_planes = num_planes_from_format(src_format); + _src_num_planes = num_planes_from_format(src_format); + _dst_num_planes = num_planes_from_format(dst_format); // Create tensors MultiImageType ref_src = create_multi_image<MultiImageType>(shape, src_format); - TensorType dst = create_tensor<TensorType>(shape, dst_format); + MultiImageType ref_dst = create_multi_image<MultiImageType>(shape, dst_format); // Create and configure function FunctionType color_convert; - if(1U == num_planes) + if(1U == _src_num_planes) { const TensorType *plane_src = static_cast<TensorType *>(ref_src.plane(0)); - color_convert.configure(plane_src, &dst); + + if(1U == _dst_num_planes) + { + TensorType *dst_plane = static_cast<TensorType *>(ref_dst.plane(0)); + color_convert.configure(plane_src, dst_plane); + } + else + { + color_convert.configure(plane_src, &ref_dst); + } } else { - color_convert.configure(&ref_src, &dst); + if(1U == _dst_num_planes) + { + TensorType *dst_plane = static_cast<TensorType *>(ref_dst.plane(0)); + color_convert.configure(&ref_src, dst_plane); + } + else + { + color_convert.configure(&ref_src, &ref_dst); + } } - for(unsigned int plane_idx = 0; plane_idx < num_planes; ++plane_idx) + for(unsigned int plane_idx = 0; plane_idx < _src_num_planes; ++plane_idx) { const TensorType *src_plane = static_cast<const TensorType *>(ref_src.plane(plane_idx)); ARM_COMPUTE_EXPECT(src_plane->info()->is_resizable(), framework::LogLevel::ERRORS); } + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + const TensorType *dst_plane = static_cast<const TensorType *>(ref_dst.plane(plane_idx)); - ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(dst_plane->info()->is_resizable(), framework::LogLevel::ERRORS); + } // Allocate tensors ref_src.allocate(); - dst.allocator()->allocate(); + ref_dst.allocate(); - for(unsigned int plane_idx = 0; plane_idx < num_planes; ++plane_idx) + for(unsigned int plane_idx = 0; plane_idx < _src_num_planes; ++plane_idx) { const TensorType *src_plane = static_cast<const TensorType *>(ref_src.plane(plane_idx)); - ARM_COMPUTE_EXPECT(!src_plane->info()->is_resizable(), framework::LogLevel::ERRORS); } - ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS); + for(unsigned int plane_idx = 0; plane_idx < _dst_num_planes; ++plane_idx) + { + const TensorType *dst_plane = static_cast<const TensorType *>(ref_dst.plane(plane_idx)); + ARM_COMPUTE_EXPECT(!dst_plane->info()->is_resizable(), framework::LogLevel::ERRORS); + } // Fill tensor planes - for(unsigned int plane_idx = 0; plane_idx < num_planes; ++plane_idx) + for(unsigned int plane_idx = 0; plane_idx < _src_num_planes; ++plane_idx) { TensorType *src_plane = static_cast<TensorType *>(ref_src.plane(plane_idx)); @@ -166,13 +190,11 @@ protected: // Compute function color_convert.run(); - return dst; + return ref_dst; } - SimpleTensor<T> compute_reference(const TensorShape &shape, Format src_format, Format dst_format) + std::vector<SimpleTensor<T>> compute_reference(const TensorShape &shape, Format src_format, Format dst_format) { - _num_planes = num_planes_from_format(dst_format); - // Create reference std::vector<SimpleTensor<T>> ref_src = create_tensor_planes_reference(shape, src_format); @@ -185,9 +207,10 @@ protected: return reference::color_convert<T>(shape, ref_src, src_format, dst_format); } - unsigned int _num_planes{}; - TensorType _target{}; - SimpleTensor<T> _reference{}; + unsigned int _src_num_planes{}; + unsigned int _dst_num_planes{}; + MultiImageType _target{}; + std::vector<SimpleTensor<T>> _reference{}; }; } // namespace validation } // namespace test diff --git a/tests/validation/reference/ColorConvert.cpp b/tests/validation/reference/ColorConvert.cpp index 6aa2ffa14c..8047b34688 100644 --- a/tests/validation/reference/ColorConvert.cpp +++ b/tests/validation/reference/ColorConvert.cpp @@ -35,12 +35,63 @@ namespace validation { namespace reference { +namespace +{ template <typename T> -SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector<SimpleTensor<T>> &tensor_planes, Format src_format, Format dst_format) +inline std::vector<SimpleTensor<T>> create_image_planes(const TensorShape &shape, Format format) { - // Create dst and get src tensor - SimpleTensor<T> src = tensor_planes[0]; - SimpleTensor<T> dst(shape, dst_format); + TensorShape image_shape = adjust_odd_shape(shape, format); + + std::vector<SimpleTensor<T>> image_planes; + + switch(format) + { + case Format::RGB888: + case Format::RGBA8888: + case Format::YUYV422: + case Format::UYVY422: + { + image_planes.emplace_back(image_shape, format); + break; + } + case Format::NV12: + case Format::NV21: + { + TensorShape shape_uv88 = calculate_subsampled_shape(image_shape, Format::UV88); + + image_planes.emplace_back(image_shape, Format::U8); + image_planes.emplace_back(shape_uv88, Format::UV88); + break; + } + case Format::IYUV: + { + TensorShape shape_sub2 = calculate_subsampled_shape(image_shape, Format::IYUV); + + image_planes.emplace_back(image_shape, Format::U8); + image_planes.emplace_back(shape_sub2, Format::U8); + image_planes.emplace_back(shape_sub2, Format::U8); + break; + } + case Format::YUV444: + { + image_planes.emplace_back(image_shape, Format::U8); + image_planes.emplace_back(image_shape, Format::U8); + image_planes.emplace_back(image_shape, Format::U8); + break; + } + default: + ARM_COMPUTE_ERROR("Not supported"); + break; + } + + return image_planes; +} +} // namespace + +template <typename T> +std::vector<SimpleTensor<T>> color_convert(const TensorShape &shape, const std::vector<SimpleTensor<T>> &tensor_planes, Format src_format, Format dst_format) +{ + std::vector<SimpleTensor<T>> dst = create_image_planes<T>(shape, dst_format); switch(src_format) { @@ -49,7 +100,16 @@ SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector< switch(dst_format) { case Format::RGBA8888: - colorconvert_helper::detail::colorconvert_rgb_to_rgbx(src, dst); + colorconvert_helper::detail::colorconvert_rgb_to_rgbx(tensor_planes[0], dst[0]); + break; + case Format::NV12: + colorconvert_helper::detail::colorconvert_rgb_to_nv12(tensor_planes[0], dst); + break; + case Format::IYUV: + colorconvert_helper::detail::colorconvert_rgb_to_iyuv(tensor_planes[0], dst); + break; + case Format::YUV444: + colorconvert_helper::detail::colorconvert_rgb_to_yuv4(tensor_planes[0], dst); break; default: ARM_COMPUTE_ERROR("Not Supported"); @@ -62,7 +122,16 @@ SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector< switch(dst_format) { case Format::RGB888: - colorconvert_helper::detail::colorconvert_rgbx_to_rgb(src, dst); + colorconvert_helper::detail::colorconvert_rgbx_to_rgb(tensor_planes[0], dst[0]); + break; + case Format::NV12: + colorconvert_helper::detail::colorconvert_rgb_to_nv12(tensor_planes[0], dst); + break; + case Format::IYUV: + colorconvert_helper::detail::colorconvert_rgb_to_iyuv(tensor_planes[0], dst); + break; + case Format::YUV444: + colorconvert_helper::detail::colorconvert_rgb_to_yuv4(tensor_planes[0], dst); break; default: ARM_COMPUTE_ERROR("Not Supported"); @@ -77,7 +146,13 @@ SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector< { case Format::RGB888: case Format::RGBA8888: - colorconvert_helper::detail::colorconvert_yuyv_to_rgb(src, src_format, dst); + colorconvert_helper::detail::colorconvert_yuyv_to_rgb(tensor_planes[0], src_format, dst[0]); + break; + case Format::NV12: + colorconvert_helper::detail::colorconvert_yuyv_to_nv12(tensor_planes[0], src_format, dst); + break; + case Format::IYUV: + colorconvert_helper::detail::colorconvert_yuyv_to_iyuv(tensor_planes[0], src_format, dst); break; default: ARM_COMPUTE_ERROR("Not Supported"); @@ -91,7 +166,7 @@ SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector< { case Format::RGB888: case Format::RGBA8888: - colorconvert_helper::detail::colorconvert_iyuv_to_rgb(shape, tensor_planes, dst); + colorconvert_helper::detail::colorconvert_iyuv_to_rgb(shape, tensor_planes, dst[0]); break; default: ARM_COMPUTE_ERROR("Not Supported"); @@ -106,7 +181,13 @@ SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector< { case Format::RGB888: case Format::RGBA8888: - colorconvert_helper::detail::colorconvert_nv12_to_rgb(shape, src_format, tensor_planes, dst); + colorconvert_helper::detail::colorconvert_nv12_to_rgb(shape, src_format, tensor_planes, dst[0]); + break; + case Format::IYUV: + colorconvert_helper::detail::colorconvert_nv_to_iyuv(tensor_planes, src_format, dst); + break; + case Format::YUV444: + colorconvert_helper::detail::colorconvert_nv_to_yuv4(tensor_planes, src_format, dst); break; default: ARM_COMPUTE_ERROR("Not Supported"); @@ -118,11 +199,10 @@ SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector< ARM_COMPUTE_ERROR("Not supported"); break; } - return dst; } -template SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector<SimpleTensor<uint8_t>> &tensor_planes, Format src_format, Format dst_format); +template std::vector<SimpleTensor<uint8_t>> color_convert(const TensorShape &shape, const std::vector<SimpleTensor<uint8_t>> &tensor_planes, Format src_format, Format dst_format); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/ColorConvert.h b/tests/validation/reference/ColorConvert.h index 2a8602e7ab..a49bbba7b9 100644 --- a/tests/validation/reference/ColorConvert.h +++ b/tests/validation/reference/ColorConvert.h @@ -35,7 +35,7 @@ namespace validation namespace reference { template <typename T> -SimpleTensor<uint8_t> color_convert(const TensorShape &shape, const std::vector<SimpleTensor<T>> &tensor_planes, Format src_format, Format dst_format); +std::vector<SimpleTensor<T>> color_convert(const TensorShape &shape, const std::vector<SimpleTensor<T>> &tensor_planes, Format src_format, Format dst_format); } // namespace reference } // namespace validation } // namespace test 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 <typename T> +inline void store_rgb_from_src(const SimpleTensor<T> src, SimpleTensor<T> &rvec, SimpleTensor<T> &gvec, SimpleTensor<T> &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<const T *>(src(src_coord)); + auto *rvec_pixel = reinterpret_cast<T *>(rvec(vec_coord)); + auto *gvec_pixel = reinterpret_cast<T *>(gvec(vec_coord)); + auto *bvec_pixel = reinterpret_cast<T *>(bvec(vec_coord)); + + rvec_pixel[0] = src_pixel[0]; + gvec_pixel[0] = src_pixel[1]; + bvec_pixel[0] = src_pixel[2]; + } + } +} + +template <typename T> +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, + SimpleTensor<T> &vvec_top, SimpleTensor<T> &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<T *>(yvec(coord)); + auto *uvec_top_pixel = reinterpret_cast<T *>(uvec_top(uvec_coord)); + auto *uvec_bottom_pixel = reinterpret_cast<T *>(uvec_bottom(uvec_coord)); + auto *vvec_top_pixel = reinterpret_cast<T *>(vvec_top(uvec_coord)); + auto *vvec_bottom_pixel = reinterpret_cast<T *>(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 <typename T> 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) { @@ -59,9 +140,9 @@ inline void yuyv_to_rgb_calculation(const SimpleTensor<T> 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<const T *>(tensor_planes[1](src_coord)); + const auto *u_pixel = reinterpret_cast<const T *>(tensor_planes[1](src_coord)); + const auto *v_pixel = reinterpret_cast<const T *>(tensor_planes[2](src_coord)); auto *uvec_pixel_top = reinterpret_cast<T *>(uvec(top_elem_coord)); auto *vvec_pixel_top = reinterpret_cast<T *>(vvec(top_elem_coord)); auto *uvec_pixel_bottom = reinterpret_cast<T *>(uvec(bottom_elem_coord)); auto *vvec_pixel_bottom = reinterpret_cast<T *>(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 <typename T> +inline void colorconvert_rgb_to_nv12(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst) +{ + SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + + int vec_shape_x = src.shape().x() * src.shape().y(); + + SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> 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<T> utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8); + SimpleTensor<T> 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<T *>(utmp(coord)); + auto *vtmp_pixel = reinterpret_cast<T *>(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<T *>(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 <typename T> +inline void colorconvert_rgb_to_iyuv(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst) +{ + SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + + int vec_shape_x = src.shape().x() * src.shape().y(); + + SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> 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<T> utmp(TensorShape{ src.shape().x() / 2, src.shape().y() }, Format::U8); + SimpleTensor<T> 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<T *>(utmp(coord)); + auto *vtmp_pixel = reinterpret_cast<T *>(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<T *>(dst[1](coord)); + auto *v_pixel = reinterpret_cast<T *>(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 <typename T> +inline void colorconvert_rgb_to_yuv4(const SimpleTensor<T> src, std::vector<SimpleTensor<T>> &dst) +{ + SimpleTensor<T> rvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> gvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> bvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + SimpleTensor<T> yvec(TensorShape{ dst[0].shape().x(), dst[0].shape().y() }, Format::U8); + + int vec_shape_x = src.shape().x() * src.shape().y(); + + SimpleTensor<T> uvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> uvec_bottom(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> vvec_top(TensorShape{ vec_shape_x, 1U }, Format::U8); + SimpleTensor<T> 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<T *>(dst[1](coord)); + auto *plane_2_pixel = reinterpret_cast<T *>(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 <typename T> +inline void colorconvert_yuyv_to_nv12(const SimpleTensor<T> src, const Format format, std::vector<SimpleTensor<T>> &dst) +{ + SimpleTensor<T> uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8); + SimpleTensor<T> 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<const T *>(src(dst_coord)); + auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord)); + auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord)); + auto *uvvec_bottom_pixel = reinterpret_cast<T *>(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<T *>(dst[1](dst_coord)); + const auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord)); + const auto *uvvec_bottom_pixel = reinterpret_cast<T *>(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 <typename T> +inline void colorconvert_yuyv_to_iyuv(const SimpleTensor<T> src, const Format format, std::vector<SimpleTensor<T>> &dst) +{ + SimpleTensor<T> uvvec_top(TensorShape{ dst[0].shape().x(), dst[0].shape().y() / 2 }, Format::U8); + SimpleTensor<T> 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<const T *>(src(dst_coord)); + auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord)); + auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord)); + auto *uvvec_bottom_pixel = reinterpret_cast<T *>(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<T *>(dst[1](dst_coord)); + auto *v_pixel = reinterpret_cast<T *>(dst[2](dst_coord)); + const auto *uvvec_top_pixel = reinterpret_cast<T *>(uvvec_top(uv_coord)); + const auto *uvvec_bottom_pixel = reinterpret_cast<T *>(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 <typename T> +inline void nv_to_iyuv(const SimpleTensor<T> src, const Format src_format, SimpleTensor<T> &nv1, SimpleTensor<T> &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<const T *>(src(src_coord)); + auto *u_pixel = reinterpret_cast<T *>(nv1(src_coord)); + auto *v_pixel = reinterpret_cast<T *>(nv2(src_coord)); + + u_pixel[0] = src_pixel[1 - offset]; + v_pixel[0] = src_pixel[0 + offset]; + } + } +} + +template <typename T> +inline void nv_to_yuv4(const SimpleTensor<T> src, const Format src_format, SimpleTensor<T> &nv1, SimpleTensor<T> &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<const T *>(src(src_coord)); + auto *u_pixel = reinterpret_cast<T *>(nv1(dst_coord)); + auto *v_pixel = reinterpret_cast<T *>(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<T *>(nv1(dst_coord)); + v_pixel = reinterpret_cast<T *>(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 <typename T> +inline void colorconvert_nv_to_iyuv(const std::vector<SimpleTensor<T>> src, const Format src_format, std::vector<SimpleTensor<T>> &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<const T *>(src[0](dst_coord)); + auto *y_pixel = reinterpret_cast<T *>(dst[0](dst_coord)); + + y_pixel[0] = src_pixel[0]; + } + } + + nv_to_iyuv(src[1], src_format, dst[1], dst[2]); +} + +template <typename T> +inline void colorconvert_nv_to_yuv4(const std::vector<SimpleTensor<T>> src, const Format src_format, std::vector<SimpleTensor<T>> &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<const T *>(src[0](dst_coord)); + auto *y_pixel = reinterpret_cast<T *>(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 |