diff --git a/docs/template_plugin/tests/functional/CMakeLists.txt b/docs/template_plugin/tests/functional/CMakeLists.txt index 8267591b98f..85f40435461 100644 --- a/docs/template_plugin/tests/functional/CMakeLists.txt +++ b/docs/template_plugin/tests/functional/CMakeLists.txt @@ -21,16 +21,14 @@ addIeTargetTest( TEMPLATE ) -if(ENABLE_TEMPLATE_OPENCV_TESTS) - find_package(OpenCV QUIET COMPONENTS core imgproc) +find_package(OpenCV QUIET COMPONENTS core imgproc) - if(OpenCV_FOUND) - message("-- Reference preprocessing: OpenCV tests are enabled") - target_compile_definitions(${TARGET_NAME} PRIVATE OPENCV_TEMPLATE_TESTS) - target_link_libraries(${TARGET_NAME} PRIVATE opencv_imgproc opencv_core) - else() - message("-- Reference preprocessing: OpenCV tests are disabled") - endif() +if(OpenCV_FOUND) + message("-- Reference preprocessing: OpenCV tests are enabled") + target_compile_definitions(${TARGET_NAME} PRIVATE OPENCV_TEMPLATE_TESTS) + target_link_libraries(${TARGET_NAME} PRIVATE opencv_imgproc opencv_core) +else() + message("-- Reference preprocessing: OpenCV tests are disabled") endif() # [cmake:functional_tests] diff --git a/docs/template_plugin/tests/functional/subgraph_reference/preprocess_opencv.cpp b/docs/template_plugin/tests/functional/subgraph_reference/preprocess_opencv.cpp index 75c3a006654..cf9abb1adae 100644 --- a/docs/template_plugin/tests/functional/subgraph_reference/preprocess_opencv.cpp +++ b/docs/template_plugin/tests/functional/subgraph_reference/preprocess_opencv.cpp @@ -26,6 +26,10 @@ public: void SetUp() override { SKIP_IF_CURRENT_TEST_IS_DISABLED() } +}; + +class PreprocessOpenCVReferenceTest_NV12 : public PreprocessOpenCVReferenceTest { +public: void Validate() override { threshold = 1.f; abs_threshold = 1.f; @@ -40,7 +44,7 @@ public: } // namespace -static std::shared_ptr create_simple_function_nv12(element::Type type, const PartialShape& shape) { +static std::shared_ptr create_simple_function(element::Type type, const PartialShape& shape) { auto data1 = std::make_shared(type, shape); data1->set_friendly_name("input1"); data1->get_output_tensor(0).set_names({"tensor_input1", "input1"}); @@ -49,11 +53,11 @@ static std::shared_ptr create_simple_function_nv12(element::Type type, op->set_friendly_name("Add0"); auto res = std::make_shared(op); res->set_friendly_name("Result1"); - res->get_output_tensor(0).set_names({"tensor_output1", "Result1", "Convert1"}); + res->get_output_tensor(0).set_names({"tensor_output1", "Result1"}); return std::make_shared(ResultVector{res}, ParameterVector{data1}); } -TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_full_color_range) { +TEST_F(PreprocessOpenCVReferenceTest_NV12, convert_nv12_full_color_range) { size_t height = 64; // 64/2 = 32 values for R size_t width = 64; // 64/2 = 32 values for G int b_step = 5; @@ -64,7 +68,7 @@ TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_full_color_range) { auto full_height = height * b_dim; auto func_shape = Shape{1, full_height, width, 3}; - function = create_simple_function_nv12(element::u8, func_shape); + function = create_simple_function(element::u8, func_shape); inputData.clear(); @@ -90,10 +94,10 @@ TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_full_color_range) { Exec(); } -TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_colored) { +TEST_F(PreprocessOpenCVReferenceTest_NV12, convert_nv12_colored) { auto input_yuv = std::vector {235, 81, 235, 81, 109, 184}; auto func_shape = Shape{1, 2, 2, 3}; - function = create_simple_function_nv12(element::u8, func_shape); + function = create_simple_function(element::u8, func_shape); inputData.clear(); @@ -116,4 +120,136 @@ TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_colored) { Exec(); } +TEST_F(PreprocessOpenCVReferenceTest, resize_u8_simple_linear) { + auto input_shape = Shape{1, 1, 2, 2}; + auto func_shape = Shape{1, 1, 1, 1}; + auto input_img = std::vector {5, 5, 5, 4}; + function = create_simple_function(element::u8, func_shape); + + inputData.clear(); + + function = PrePostProcessor().input(InputInfo() + .tensor(InputTensorInfo().set_spatial_static_shape(2, 2)) + .preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_LINEAR)) + .network(InputNetworkInfo().set_layout("NCHW")) + ) + .build(function); + + const auto ¶m = function->get_parameters()[0]; + inputData.emplace_back(param->get_element_type(), param->get_shape(), input_img.data()); + + // Calculate reference expected values from OpenCV + cv::Mat cvPic = cv::Mat(2, 2, CV_8UC1, input_img.data()); + cv::Mat cvPicResized; + cv::resize(cvPic, cvPicResized, cv::Size(1, 1), cv::INTER_NEAREST); + refOutData.emplace_back(param->get_element_type(), func_shape, cvPicResized.data); + // Exec now + Exec(); +} + +TEST_F(PreprocessOpenCVReferenceTest, resize_u8_large_picture_linear) { + threshold = 1.f; + abs_threshold = 1.f; // Some pixels still have deviations of 1 step + const size_t input_height = 50; + const size_t input_width = 50; + const size_t func_height = 37; + const size_t func_width = 31; + auto input_shape = Shape{1, 1, input_height, input_width}; + auto func_shape = Shape{1, 1, func_height, func_width}; + auto input_img = std::vector (shape_size(input_shape)); + std::default_random_engine random(0); // hard-coded seed to make test results predictable + std::uniform_int_distribution distrib(0, 255); + for (std::size_t i = 0; i < shape_size(input_shape); i++) { + auto v = distrib(random); + input_img[i] = static_cast(v); + } + function = create_simple_function(element::u8, func_shape); + + inputData.clear(); + + function = PrePostProcessor().input(InputInfo() + .tensor(InputTensorInfo().set_spatial_static_shape(input_height, input_width)) + .preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_LINEAR)) + .network(InputNetworkInfo().set_layout("NCHW")) + ) + .build(function); + + const auto ¶m = function->get_parameters()[0]; + inputData.emplace_back(param->get_element_type(), param->get_shape(), input_img.data()); + + // Calculate reference expected values from OpenCV + cv::Mat cvPic = cv::Mat(input_height, input_width, CV_8UC1, input_img.data()); + cv::Mat cvPicResized; + cv::resize(cvPic, cvPicResized, cv::Size(func_width, func_height), cv::INTER_LINEAR_EXACT); + refOutData.emplace_back(param->get_element_type(), func_shape, cvPicResized.data); + // Exec now + Exec(); +} + +TEST_F(PreprocessOpenCVReferenceTest, resize_f32_large_picture_linear) { + threshold = 0.01f; + abs_threshold = 0.01f; + const size_t input_height = 50; + const size_t input_width = 50; + const size_t func_height = 37; + const size_t func_width = 31; + auto input_shape = Shape{1, 1, input_height, input_width}; + auto func_shape = Shape{1, 1, func_height, func_width}; + auto input_img = std::vector (shape_size(input_shape)); + std::default_random_engine random(0); // hard-coded seed to make test results predictable + std::uniform_int_distribution distrib(0, 255); + for (std::size_t i = 0; i < shape_size(input_shape); i++) { + input_img[i] = static_cast(distrib(random)); + } + function = create_simple_function(element::f32, func_shape); + + inputData.clear(); + + function = PrePostProcessor().input(InputInfo() + .tensor(InputTensorInfo().set_spatial_static_shape(input_height, input_width)) + .preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_LINEAR)) + .network(InputNetworkInfo().set_layout("NCHW")) + ) + .build(function); + + const auto ¶m = function->get_parameters()[0]; + inputData.emplace_back(param->get_element_type(), param->get_shape(), input_img.data()); + + // Calculate reference expected values from OpenCV + cv::Mat cvPic = cv::Mat(input_height, input_width, CV_32FC1, input_img.data()); + cv::Mat cvPicResized; + cv::resize(cvPic, cvPicResized, cv::Size(func_width, func_height), cv::INTER_LINEAR_EXACT); + refOutData.emplace_back(param->get_element_type(), func_shape, cvPicResized.data); + // Exec now + Exec(); +} + +TEST_F(PreprocessOpenCVReferenceTest, DISABLED_resize_f32_large_picture_cubic_small) { + const size_t input_height = 4; + const size_t input_width = 4; + const size_t func_height = 3; + const size_t func_width = 3; + auto input_shape = Shape{1, 1, input_height, input_width}; + auto func_shape = Shape{1, 1, func_height, func_width}; + auto element_type = element::f32; + auto input_img = std::vector {1.f, 2.f, 3.f, 4.f, 4.f, 3.f, 2.f, 1.f, 1.f, 2.f, 3.f, 4.f, 4.f, 3.f, 2.f, 1.f}; + function = create_simple_function(element_type, func_shape); + function = PrePostProcessor().input(InputInfo() + .tensor(InputTensorInfo().set_spatial_static_shape(input_height, input_width)) + .preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_CUBIC)) + .network(InputNetworkInfo().set_layout("NCHW")) + ) + .build(function); + + inputData.emplace_back(element_type, input_shape, input_img.data()); + + // Calculate reference expected values from OpenCV + cv::Mat cvPic = cv::Mat(input_height, input_width, CV_32FC1, input_img.data()); + cv::Mat cvPicResized; + cv::resize(cvPic, cvPicResized, cv::Size(func_width, func_height), cv::INTER_CUBIC); + refOutData.emplace_back(element_type, func_shape, cvPicResized.data); + // Exec now + Exec(); +} + #endif // OPENCV_TEMPLATE_TESTS \ No newline at end of file diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/interpolate.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/interpolate.hpp index 33a45e6c04a..770c94678e5 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/interpolate.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/interpolate.hpp @@ -372,7 +372,12 @@ void InterpolateEval::linear_func(const T* input_data, T* out) { if (wsum == 0.0f) { out[output_transform.index(output_coord)] = T{}; } else { - out[output_transform.index(output_coord)] = static_cast(summa / wsum); + if (std::is_integral()) { + // Round value for integral return types + out[output_transform.index(output_coord)] = static_cast(std::round(summa / wsum)); + } else { + out[output_transform.index(output_coord)] = static_cast(summa / wsum); + } } } NGRAPH_SUPPRESS_DEPRECATED_END diff --git a/ngraph/core/src/op/interpolate.cpp b/ngraph/core/src/op/interpolate.cpp index 720233582c8..d244f265b42 100644 --- a/ngraph/core/src/op/interpolate.cpp +++ b/ngraph/core/src/op/interpolate.cpp @@ -201,10 +201,10 @@ ov::PartialShape op::v4::Interpolate::get_padded_input_shape(const ov::PartialSh void op::v4::Interpolate::validate_and_infer_types() { NGRAPH_OP_SCOPE(v4_Interpolate_validate_and_infer_types); element::Type input_et = get_input_element_type(0); - NODE_VALIDATION_CHECK( - this, - input_et == element::f32 || input_et == element::f16 || input_et == element::i8 || input_et == element::bf16, - "Input element type must be f32, f16, bf16 or i8"); + NODE_VALIDATION_CHECK(this, + input_et == element::f32 || input_et == element::f16 || input_et == element::i8 || + input_et == element::bf16 || input_et == element::u8, + "Input element type must be f32, f16, bf16, i8 or u8"); element::Type sizes_et = get_input_element_type(1); NODE_VALIDATION_CHECK( @@ -454,6 +454,14 @@ bool op::v4::Interpolate::evaluate_interpolate(const HostTensorVector& outputs, outputs[0]->get_data_ptr(), out_shape, m_attrs); + case element::Type_t::u8: + ngraph::runtime::reference::interpolate(reinterpret_cast(padded_data_ptr), + padded_input_shape, + scales, + axes, + outputs[0]->get_data_ptr(), + out_shape, + m_attrs); break; default:; } @@ -469,6 +477,7 @@ bool op::v4::Interpolate::evaluate(const HostTensorVector& outputs, const HostTe bool op::v4::Interpolate::has_evaluate() const { NGRAPH_OP_SCOPE(v4_Interpolate_has_evaluate); switch (get_input_element_type(0)) { + case ngraph::element::i8: case ngraph::element::u8: case ngraph::element::f16: case ngraph::element::f32: