diff options
Diffstat (limited to 'tests/validation')
-rw-r--r-- | tests/validation/CL/ColorConvert.cpp | 170 | ||||
-rw-r--r-- | tests/validation/NEON/ColorConvert.cpp | 173 | ||||
-rw-r--r-- | tests/validation/fixtures/ColorConvertFixture.h | 195 | ||||
-rw-r--r-- | tests/validation/reference/ColorConvert.cpp | 134 | ||||
-rw-r--r-- | tests/validation/reference/ColorConvert.h | 43 | ||||
-rw-r--r-- | tests/validation/reference/ColorConvertHelper.h | 343 |
6 files changed, 1058 insertions, 0 deletions
diff --git a/tests/validation/CL/ColorConvert.cpp b/tests/validation/CL/ColorConvert.cpp new file mode 100644 index 0000000000..6d04511629 --- /dev/null +++ b/tests/validation/CL/ColorConvert.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017-2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/CL/CLMultiImage.h" +#include "arm_compute/runtime/CL/CLTensor.h" +#include "arm_compute/runtime/CL/CLTensorAllocator.h" +#include "arm_compute/runtime/CL/functions/CLColorConvert.h" +#include "tests/CL/CLAccessor.h" +#include "tests/datasets/ShapeDatasets.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" +#include "tests/validation/fixtures/ColorConvertFixture.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +// Input data sets +const auto ColorConvertRGBADataset = combine(framework::dataset::make("FormatType", { Format::RGBA8888 }), + framework::dataset::make("FormatType", { Format::RGB888 })); +const auto ColorConvertYUVDataset = combine(framework::dataset::make("FormatType", { Format::YUYV422, Format::UYVY422 }), + framework::dataset::make("FormatType", { Format::RGB888, Format::RGBA8888 })); + +const auto ColorConvertYUVPlanarDataset = combine(framework::dataset::make("FormatType", { Format::IYUV, Format::NV12, Format::NV21 }), + framework::dataset::make("FormatType", { Format::RGB888, Format::RGBA8888 })); + +const auto ColorConvertRGBDataset = combine(framework::dataset::make("FormatType", { Format::RGB888 }), + framework::dataset::make("FormatType", { Format::RGBA8888 })); + +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 TensorShape dst_shape = adjust_odd_shape(shape, src_format); + + // Create tensors + CLMultiImage ref_src = create_multi_image<CLMultiImage>(shape, src_format); + CLTensor dst = create_tensor<CLTensor>(dst_shape, dst_format); + + // Create and Configure function + CLColorConvert color_convert; + + if(1U == src_num_planes) + { + const CLTensor *plane_src = 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); + } + else + { + color_convert.configure(&ref_src, &dst); + } +} +} // namespace + +TEST_SUITE(CL) +TEST_SUITE(ColorConvert) + +TEST_SUITE(Configuration) +DATA_TEST_CASE(RGBA, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertRGBADataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(YUV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertYUVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(YUVPlanar, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertYUVPlanarDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(RGB, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertRGBDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} +TEST_SUITE_END() + +template <typename T> +using CLColorConvertFixture = ColorConvertValidationFixture<CLMultiImage, CLTensor, CLAccessor, CLColorConvert, T>; + +TEST_SUITE(RGBA) +FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBADataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference); +} + +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBADataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference); +} +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); +} +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVDataset)) +{ + validate(CLAccessor(_target), _reference); +} +TEST_SUITE_END() + +TEST_SUITE(YUVPlanar) +FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUVPlanarDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference); +} +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVPlanarDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference); +} +TEST_SUITE_END() + +TEST_SUITE(RGB) +FIXTURE_DATA_TEST_CASE(RunSmall, CLColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference); +} +FIXTURE_DATA_TEST_CASE(RunLarge, CLColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference); +} +TEST_SUITE_END() +TEST_SUITE_END() +TEST_SUITE_END() +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/NEON/ColorConvert.cpp b/tests/validation/NEON/ColorConvert.cpp new file mode 100644 index 0000000000..ab6ec5b725 --- /dev/null +++ b/tests/validation/NEON/ColorConvert.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017-2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/MultiImage.h" +#include "arm_compute/runtime/NEON/functions/NEColorConvert.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" +#include "tests/NEON/Accessor.h" +#include "tests/datasets/ShapeDatasets.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/validation/Validation.h" +#include "tests/validation/fixtures/ColorConvertFixture.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +// Input data sets +const auto ColorConvertRGBADataset = combine(framework::dataset::make("FormatType", { Format::RGBA8888 }), + framework::dataset::make("FormatType", { Format::RGB888 })); +const auto ColorConvertYUVDataset = combine(framework::dataset::make("FormatType", { Format::YUYV422, Format::UYVY422 }), + framework::dataset::make("FormatType", { Format::RGB888, Format::RGBA8888 })); + +const auto ColorConvertYUVPlanarDataset = combine(framework::dataset::make("FormatType", { Format::IYUV, Format::NV12, Format::NV21 }), + framework::dataset::make("FormatType", { Format::RGB888, Format::RGBA8888 })); + +const auto ColorConvertRGBDataset = combine(framework::dataset::make("FormatType", { Format::RGB888 }), + framework::dataset::make("FormatType", { Format::RGBA8888 })); + +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 TensorShape dst_shape = adjust_odd_shape(shape, src_format); + + // Create tensors + MultiImage ref_src = create_multi_image<MultiImage>(shape, src_format); + Tensor dst = create_tensor<Tensor>(dst_shape, dst_format); + + // Create and Configure function + NEColorConvert color_convert; + + if(1U == src_num_planes) + { + const Tensor *plane_src = 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); + } + else + { + color_convert.configure(&ref_src, &dst); + } +} +} // namespace + +TEST_SUITE(NEON) +TEST_SUITE(ColorConvert) + +TEST_SUITE(Configuration) +DATA_TEST_CASE(RGBA, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertRGBADataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(YUV, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertYUVDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(YUVPlanar, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertYUVPlanarDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} + +DATA_TEST_CASE(RGB, framework::DatasetMode::ALL, combine(concat(datasets::Small2DShapes(), datasets::Large2DShapes()), ColorConvertRGBDataset), + shape, src_format, dst_format) +{ + validate_configuration(shape, src_format, dst_format); +} +TEST_SUITE_END() + +template <typename T> +using NEColorConvertFixture = ColorConvertValidationFixture<MultiImage, Tensor, Accessor, NEColorConvert, T>; + +TEST_SUITE(RGBA) +FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBADataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBADataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} + +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); +} +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVDataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} + +TEST_SUITE_END() + +TEST_SUITE(YUVPlanar) +FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertYUVPlanarDataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertYUVPlanarDataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} +TEST_SUITE_END() + +TEST_SUITE(RGB) +FIXTURE_DATA_TEST_CASE(RunSmall, NEColorConvertFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(datasets::Small2DShapes(), ColorConvertRGBDataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} +FIXTURE_DATA_TEST_CASE(RunLarge, NEColorConvertFixture<uint8_t>, framework::DatasetMode::NIGHTLY, combine(datasets::Large2DShapes(), ColorConvertRGBDataset)) +{ + // Validate output + validate(Accessor(_target), _reference); +} +TEST_SUITE_END() + +TEST_SUITE_END() +TEST_SUITE_END() +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/fixtures/ColorConvertFixture.h b/tests/validation/fixtures/ColorConvertFixture.h new file mode 100644 index 0000000000..bd00d4f724 --- /dev/null +++ b/tests/validation/fixtures/ColorConvertFixture.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2017-2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef ARM_COMPUTE_TEST_COLOR_CONVERT_FIXTURE +#define ARM_COMPUTE_TEST_COLOR_CONVERT_FIXTURE + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/IAccessor.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Fixture.h" +#include "tests/validation/Helpers.h" +#include "tests/validation/reference/ColorConvert.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +} +template <typename MultiImageType, typename TensorType, typename AccessorType, typename FunctionType, typename T> +class ColorConvertValidationFixture : public framework::Fixture +{ +public: + template <typename...> + void setup(TensorShape shape, Format src_format, Format dst_format) + { + shape = adjust_odd_shape(shape, src_format); + + _target = compute_target(shape, src_format, dst_format); + _reference = compute_reference(shape, src_format, dst_format); + } + +protected: + template <typename U> + void fill(U &&tensor, int i) + { + library->fill_tensor_uniform(tensor, 1); + } + + 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) + { + case Format::RGB888: + case Format::RGBA8888: + case Format::YUYV422: + case Format::UYVY422: + { + tensor_planes.emplace_back(input, format); + break; + } + case Format::NV12: + case Format::NV21: + { + const TensorShape shape_uv88 = calculate_subsampled_shape(shape, Format::UV88); + + tensor_planes.emplace_back(input, Format::U8); + tensor_planes.emplace_back(shape_uv88, Format::UV88); + break; + } + case Format::IYUV: + { + const TensorShape shape_sub2 = calculate_subsampled_shape(shape, Format::IYUV); + + tensor_planes.emplace_back(input, 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); + break; + } + default: + ARM_COMPUTE_ERROR("Not supported"); + break; + } + + return tensor_planes; + } + + TensorType compute_target(const TensorShape &shape, Format src_format, Format dst_format) + { + const unsigned int num_planes = num_planes_from_format(src_format); + + // Create tensors + MultiImageType ref_src = create_multi_image<MultiImageType>(shape, src_format); + TensorType dst = create_tensor<TensorType>(shape, dst_format); + + // Create and configure function + FunctionType color_convert; + + if(1U == num_planes) + { + const TensorType *plane_src = static_cast<TensorType *>(ref_src.plane(0)); + color_convert.configure(plane_src, &dst); + } + else + { + color_convert.configure(&ref_src, &dst); + } + + for(unsigned int plane_idx = 0; plane_idx < 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); + + // Allocate tensors + ref_src.allocate(); + dst.allocator()->allocate(); + + for(unsigned int plane_idx = 0; plane_idx < 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); + + // Fill tensor planes + for(unsigned int plane_idx = 0; plane_idx < num_planes; ++plane_idx) + { + TensorType *src_plane = static_cast<TensorType *>(ref_src.plane(plane_idx)); + + fill(AccessorType(*src_plane), plane_idx); + } + + // Compute function + color_convert.run(); + + return dst; + } + + 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); + + // Fill references + for(unsigned int plane_idx = 0; plane_idx < ref_src.size(); ++plane_idx) + { + fill(ref_src[plane_idx], plane_idx); + } + + return reference::color_convert<T>(shape, ref_src, src_format, dst_format); + } + + unsigned int _num_planes{}; + TensorType _target{}; + SimpleTensor<T> _reference{}; +}; +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_COLOR_CONVERT_FIXTURE */ diff --git a/tests/validation/reference/ColorConvert.cpp b/tests/validation/reference/ColorConvert.cpp new file mode 100644 index 0000000000..bd93eb6a61 --- /dev/null +++ b/tests/validation/reference/ColorConvert.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2017-2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "ColorConvert.h" + +#include "arm_compute/core/Types.h" +#include "tests/validation/FixedPoint.h" +#include "tests/validation/Helpers.h" +#include "tests/validation/reference/ColorConvertHelper.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace reference +{ +namespace +{ +} // 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) +{ + // Create dst and get src tensor + SimpleTensor<T> src = tensor_planes[0]; + SimpleTensor<T> dst(shape, dst_format); + + switch(src_format) + { + case Format::RGB888: + { + switch(dst_format) + { + case Format::RGBA8888: + colorconvert_helper::detail::colorconvert_rgb_to_rgbx(src, dst); + break; + default: + ARM_COMPUTE_ERROR("Not Supported"); + break; + } + break; + } + case Format::RGBA8888: + { + switch(dst_format) + { + case Format::RGB888: + colorconvert_helper::detail::colorconvert_rgbx_to_rgb(src, dst); + break; + default: + ARM_COMPUTE_ERROR("Not Supported"); + break; + } + break; + } + case Format::UYVY422: + case Format::YUYV422: + { + switch(dst_format) + { + case Format::RGB888: + case Format::RGBA8888: + colorconvert_helper::detail::colorconvert_yuyv_to_rgb(src, src_format, dst); + break; + default: + ARM_COMPUTE_ERROR("Not Supported"); + break; + } + break; + } + case Format::IYUV: + { + switch(dst_format) + { + case Format::RGB888: + case Format::RGBA8888: + colorconvert_helper::detail::colorconvert_iyuv_to_rgb(shape, tensor_planes, dst); + break; + default: + ARM_COMPUTE_ERROR("Not Supported"); + break; + } + break; + } + case Format::NV12: + case Format::NV21: + { + switch(dst_format) + { + case Format::RGB888: + case Format::RGBA8888: + colorconvert_helper::detail::colorconvert_nv12_to_rgb(shape, src_format, tensor_planes, dst); + break; + default: + ARM_COMPUTE_ERROR("Not Supported"); + break; + } + break; + } + default: + 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); +} // namespace reference +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/reference/ColorConvert.h b/tests/validation/reference/ColorConvert.h new file mode 100644 index 0000000000..2a8602e7ab --- /dev/null +++ b/tests/validation/reference/ColorConvert.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017-2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_TEST_COLOR_CONVERT_H__ +#define __ARM_COMPUTE_TEST_COLOR_CONVERT_H__ + +#include "tests/SimpleTensor.h" + +namespace arm_compute +{ +namespace test +{ +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); +} // namespace reference +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_COLOR_CONVERT_H__ */ diff --git a/tests/validation/reference/ColorConvertHelper.h b/tests/validation/reference/ColorConvertHelper.h new file mode 100644 index 0000000000..4daa7025cb --- /dev/null +++ b/tests/validation/reference/ColorConvertHelper.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2017-2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *asymm_int_mult + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, asymm_int_multDAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H__ +#define __ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H__ + +#include "Utils.h" + +namespace arm_compute +{ +namespace test +{ +namespace colorconvert_helper +{ +namespace detail +{ +constexpr float red_coef_bt709 = 1.5748F; +constexpr float green_coef_bt709 = -0.1873f; +constexpr float green_coef2_bt709 = -0.4681f; +constexpr float blue_coef_bt709 = 1.8556f; + +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) +{ + const int dst_width = dst.shape().x(); + const int dst_height = dst.shape().y(); + + for(int y = 0; y < dst_height; ++y) + { + int x_coord = 0; + for(int x = 0; x < dst_width; x += 2, x_coord++) + { + Coordinates dst_coord{ x, y }; + auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord)); + float result = 0.f; + + T border_value(0); + const int yvec_val = validation::tensor_elem_at(yvec, { x_coord, y }, BorderMode::CONSTANT, border_value); + 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; + + for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx) + { + if(channel_idx == 0) + { + // Channel 'R' + result = yvec_val + red; + } + else if(channel_idx == 1) + { + // Channel 'G' + result = yvec_val + green; + } + else if(channel_idx == 2) + { + // Channel 'B' + result = yvec_val + blue; + } + else + { + // Channel 'A' + result = 255; + } + + if(result < 0) + { + result = 0; + } + else if(result > 255) + { + result = 255; + } + dst_pixel[channel_idx] = result; + } + + dst_coord.set(0, x + 1); + dst_pixel = reinterpret_cast<T *>(dst(dst_coord)); + for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx) + { + if(channel_idx == 0) + { + // Channel 'R' + result = yyvec_val + red; + } + else if(channel_idx == 1) + { + // Channel 'G' + result = yyvec_val + green; + } + else if(channel_idx == 2) + { + // Channel 'B' + result = yyvec_val + blue; + } + else + { + // Channel 'A' + result = 255; + } + + if(result < 0) + { + result = 0; + } + else if(result > 255) + { + result = 255; + } + dst_pixel[channel_idx] = result; + } + } + } +} + +template <typename T> +inline void colorconvert_rgb_to_rgbx(const SimpleTensor<T> src, SimpleTensor<T> &dst) +{ + for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx) + { + const int width = dst.shape().x(); + const int height = dst.shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; ++x) + { + const Coordinates src_coord{ x, y }; + const Coordinates dst_coord{ x, y }; + + const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord)); + auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord)); + if(channel_idx == 3) + { + dst_pixel[channel_idx] = 255; + continue; + } + + dst_pixel[channel_idx] = src_pixel[channel_idx]; + } + } + } +} + +template <typename T> +inline void colorconvert_rgbx_to_rgb(const SimpleTensor<T> src, SimpleTensor<T> &dst) +{ + for(int channel_idx = 0; channel_idx < dst.num_channels(); ++channel_idx) + { + const int width = dst.shape().x(); + const int height = dst.shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; ++x) + { + const Coordinates src_coord{ x, y }; + const Coordinates dst_coord{ x, y }; + + const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord)); + auto *dst_pixel = reinterpret_cast<T *>(dst(dst_coord)); + + dst_pixel[channel_idx] = src_pixel[channel_idx]; + } + } + } +} + +template <typename T> +inline void colorconvert_yuyv_to_rgb(const SimpleTensor<T> src, const Format format, SimpleTensor<T> &dst) +{ + SimpleTensor<T> yvec(TensorShape{ src.shape().x(), src.shape().y() }, Format::U8); + SimpleTensor<T> uvec(TensorShape{ src.shape().x(), src.shape().y() }, Format::U8); + SimpleTensor<T> yyvec(TensorShape{ src.shape().x(), src.shape().y() }, Format::U8); + SimpleTensor<T> vvec(TensorShape{ src.shape().x(), src.shape().y() }, Format::U8); + + const int step_x = (Format::YUYV422 == format || Format::UYVY422 == format) ? 2 : 1; + + const int offset = (Format::YUYV422 == format) ? 0 : 1; + Coordinates elem_coord{ 0, 0 }; + + const int width = vvec.shape().x(); + const int height = vvec.shape().y(); + + for(int y = 0; y < height; ++y) + { + for(int x = 0; x < width; ++x) + { + const Coordinates src_coord{ x * step_x, y }; + const auto *src_pixel = reinterpret_cast<const T *>(src(src_coord)); + auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord)); + auto *uvec_pixel = reinterpret_cast<T *>(uvec(elem_coord)); + auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord)); + auto *vvec_pixel = reinterpret_cast<T *>(vvec(elem_coord)); + yvec_pixel[x] = src_pixel[0 + offset]; + uvec_pixel[x] = src_pixel[1 - offset]; + yyvec_pixel[x] = src_pixel[2 + offset]; + vvec_pixel[x] = src_pixel[3 - offset]; + } + elem_coord.set(1, y + 1); + } + + yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst); +} + +template <typename T> +inline void colorconvert_iyuv_to_rgb(const TensorShape &shape, const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst) +{ + SimpleTensor<T> yvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + SimpleTensor<T> uvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + SimpleTensor<T> yyvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + SimpleTensor<T> vvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + + Coordinates elem_coord{ 0, 0 }; + const int yvec_width = yvec.shape().x(); + const int yvec_height = yvec.shape().y(); + + for(int y = 0; y < yvec_height; ++y) + { + for(int x = 0; x < yvec_width; ++x) + { + const Coordinates src_coord{ x, y }; + const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[0](src_coord)); + auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord)); + auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord)); + yvec_pixel[x] = src_pixel[x]; + yyvec_pixel[x] = src_pixel[x + 1]; + } + elem_coord.set(1, y + 1); + } + + const int uvec_width = uvec.shape().x(); + const int uvec_height = uvec.shape().y(); + + Coordinates top_elem_coord{ 0, 0 }; + Coordinates bottom_elem_coord{ 0, 1 }; + for(int y = 0; y < uvec_height; y += 2) + { + 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)); + 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]; + } + top_elem_coord.set(1, y + 2); + bottom_elem_coord.set(1, top_elem_coord.y() + 1); + } + + yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst); +} + +template <typename T> +inline void colorconvert_nv12_to_rgb(const TensorShape &shape, const Format format, const std::vector<SimpleTensor<T>> &tensor_planes, SimpleTensor<T> &dst) +{ + SimpleTensor<T> yvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + SimpleTensor<T> uvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + SimpleTensor<T> yyvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + SimpleTensor<T> vvec(TensorShape{ tensor_planes[0].shape().x(), tensor_planes[0].shape().y() }, Format::U8); + + const int offset = (Format::NV12 == format) ? 0 : 1; + + Coordinates elem_coord{ 0, 0 }; + const int yvec_width = yvec.shape().x(); + const int yvec_height = yvec.shape().y(); + + for(int y = 0; y < yvec_height; ++y) + { + for(int x = 0; x < yvec_width; ++x) + { + const Coordinates src_coord{ x, y }; + const auto *src_pixel = reinterpret_cast<const T *>(tensor_planes[0](src_coord)); + auto *yvec_pixel = reinterpret_cast<T *>(yvec(elem_coord)); + auto *yyvec_pixel = reinterpret_cast<T *>(yyvec(elem_coord)); + yvec_pixel[x] = src_pixel[x]; + yyvec_pixel[x] = src_pixel[x + 1]; + } + elem_coord.set(1, y + 1); + } + + const int uvec_width = uvec.shape().x(); + const int uvec_height = uvec.shape().y(); + + Coordinates top_elem_coord{ 0, 0 }; + Coordinates bottom_elem_coord{ 0, 1 }; + for(int y = 0; y < uvec_height; y += 2) + { + 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)); + 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 + offset]; + vvec_pixel_top[x] = src_pixel[1 - offset]; + uvec_pixel_bottom[x] = src_pixel[0 + offset]; + vvec_pixel_bottom[x] = src_pixel[1 - offset]; + } + top_elem_coord.set(1, y + 2); + bottom_elem_coord.set(1, top_elem_coord.y() + 1); + } + + yuyv_to_rgb_calculation(yvec, vvec, yyvec, uvec, dst); +} + +} // namespace detail +} // color_convert_helper +} // namespace test +} // namespace arm_compute +#endif /*__ARM_COMPUTE_TEST_VALIDATION_COLOR_CONVERT_H__ */ |