From 4387e8bf15b249bf4fda62637f4b66cee839ce81 Mon Sep 17 00:00:00 2001 From: Piotr Kowalczyk Date: Thu, 25 Apr 2024 09:08:33 +0200 Subject: [PATCH] [Op]: ROIAlignRotated ref implementation (#23607) ### Details: - added reference impl of ROIAlignRotated. ### Tickets: - *[CVS-135725]* --------- Co-authored-by: Pawel Raasz Co-authored-by: Michal Lukaszewski --- .../include/openvino/reference/roi_align.hpp | 241 +++++++++++--- .../template/backend/ops/ops_evaluates.hpp | 4 + .../backend/ops/roi_align_rotated.cpp | 54 ++++ .../template/backend/opset_int_tbl.hpp | 1 + .../op_reference/roi_align_rotated.cpp | 303 ++++++++++++++++++ 5 files changed, 563 insertions(+), 40 deletions(-) create mode 100644 src/plugins/template/backend/ops/roi_align_rotated.cpp create mode 100644 src/plugins/template/tests/functional/op_reference/roi_align_rotated.cpp diff --git a/src/core/reference/include/openvino/reference/roi_align.hpp b/src/core/reference/include/openvino/reference/roi_align.hpp index 583d6b7ae6e..8e0a76af108 100644 --- a/src/core/reference/include/openvino/reference/roi_align.hpp +++ b/src/core/reference/include/openvino/reference/roi_align.hpp @@ -15,7 +15,189 @@ namespace ov { namespace reference { using ROIPoolingMode = op::v3::ROIAlign::PoolingMode; using AlignedMode = op::v9::ROIAlign::AlignedMode; + +namespace roi_policy { + +// Base class for representing sampling space. +// Sampling space is defined as aligned bounding box. template +class SamplingSpaceBase { +public: + T get_start_x() const { + return start_x; + } + T get_start_y() const { + return start_y; + } + T get_size_x() const { + return size_x; + } + T get_size_y() const { + return size_y; + } + +protected: + SamplingSpaceBase(T start_x_, T start_y_, T size_x_, T size_y_) + : start_x(start_x_), + start_y(start_y_), + size_x(size_x_), + size_y(size_y_) {} + + T start_x; + T start_y; + T size_x; + T size_y; +}; + +template +struct Point { + T x; + T y; +}; + +template +class ROIAlignOpDefPolicy { +public: + class ROIAlignSamplingSpace : public SamplingSpaceBase { + public: + Point transform_sampling_point_to_image_space(const Point& point) const { + return point; + } + + private: + friend class ROIAlignOpDefPolicy; + ROIAlignSamplingSpace(T start_x_, T start_y_, T size_x_, T size_y_) + : SamplingSpaceBase(start_x_, start_y_, size_x_, size_y_) {} + }; + + ROIAlignOpDefPolicy() : aligned(false), offset_src(0), offset_dst(0) {} + + void init(const T* rois_, const Shape& shape_, float spatial_scale_, AlignedMode aligned_mode, bool) { + rois = rois_; + shape = shape_; + spatial_scale = spatial_scale_; + switch (aligned_mode) { + case AlignedMode::HALF_PIXEL_FOR_NN: { + aligned = true; + offset_dst = static_cast(-0.5); + break; + } + case AlignedMode::HALF_PIXEL: { + aligned = true; + offset_src = static_cast(0.5); + offset_dst = static_cast(-0.5); + break; + } + case AlignedMode::ASYMMETRIC: { + break; + } + default: { + OPENVINO_THROW(std::string("Not supported aligned_mode")); + break; + } + } + } + + ROIAlignSamplingSpace get_sampling_space_for_index(unsigned int index) const { + T x1 = (rois[coordinate_index({index, 0}, shape)] + offset_src) * spatial_scale + offset_dst; + T y1 = (rois[coordinate_index({index, 1}, shape)] + offset_src) * spatial_scale + offset_dst; + T x2 = (rois[coordinate_index({index, 2}, shape)] + offset_src) * spatial_scale + offset_dst; + T y2 = (rois[coordinate_index({index, 3}, shape)] + offset_src) * spatial_scale + offset_dst; + + T roi_width = x2 - x1; + T roi_height = y2 - y1; + + if (!aligned) { + roi_width = std::max(roi_width, static_cast(1.0)); + roi_height = std::max(roi_height, static_cast(1.0)); + } + + return {x1, y1, roi_width, roi_height}; + } + +private: + const T* rois; + Shape shape; + float spatial_scale; + bool aligned; + T offset_src; + T offset_dst; +}; + +template +class ROIAlignRotatedOpDefPolicy { +public: + class ROIAlignRotatedSamplingSpace : public SamplingSpaceBase { + public: + Point transform_sampling_point_to_image_space(const Point& point) const { + const T y = point.y * cos_angle - point.x * sin_angle + center_y; + const T x = point.y * sin_angle + point.x * cos_angle + center_x; + return {x, y}; + } + + private: + friend class ROIAlignRotatedOpDefPolicy; + ROIAlignRotatedSamplingSpace(T center_x_, + T center_y_, + T cos_angle_, + T sin_angle_, + T start_x_, + T start_y_, + T size_x_, + T size_y_) + : SamplingSpaceBase(start_x_, start_y_, size_x_, size_y_), + center_x(center_x_), + center_y(center_y_), + cos_angle(cos_angle_), + sin_angle(sin_angle_) {} + + T center_x; + T center_y; + T cos_angle; + T sin_angle; + }; + + ROIAlignRotatedOpDefPolicy() {} + + void init(const T* rois_, const Shape& shape_, float spatial_scale_, AlignedMode aligned_mode, bool clockwise_) { + rois = rois_; + shape = shape_; + spatial_scale = static_cast(spatial_scale_); + clockwise = clockwise_; + + if (aligned_mode != AlignedMode::ASYMMETRIC) { + OPENVINO_THROW("ROIAlignRotated: Not supported aligned_mode"); + } + } + + ROIAlignRotatedSamplingSpace get_sampling_space_for_index(unsigned int index) const { + const T center_x = (rois[coordinate_index({index, 0}, shape)]) * spatial_scale - T{0.5f}; + const T center_y = (rois[coordinate_index({index, 1}, shape)]) * spatial_scale - T{0.5f}; + const T width = (rois[coordinate_index({index, 2}, shape)]) * spatial_scale; + const T height = (rois[coordinate_index({index, 3}, shape)]) * spatial_scale; + T angle = (rois[coordinate_index({index, 4}, shape)]); + + if (clockwise) { + angle = -angle; + } + const T cos_angle = cos(angle); + const T sin_angle = sin(angle); + + const T x1 = -width / T{2.0}; + const T y1 = -height / T{2.0}; + + return {center_x, center_y, cos_angle, sin_angle, x1, y1, width, height}; + } + +private: + const T* rois; + Shape shape; + T spatial_scale; + bool clockwise; +}; +}; // namespace roi_policy + +template class TROIPolicy = roi_policy::ROIAlignOpDefPolicy> void roi_align(const T* feature_maps, const T* rois, const int64_t* batch_indices, @@ -29,50 +211,23 @@ void roi_align(const T* feature_maps, const int sampling_ratio, const float spatial_scale, const ROIPoolingMode& pooling_mode, - const AlignedMode& aligned_mode = AlignedMode::ASYMMETRIC) { + const AlignedMode& aligned_mode = AlignedMode::ASYMMETRIC, + bool clockwise = true) { auto C = feature_maps_shape[1]; auto feature_map_height = feature_maps_shape[2]; auto feature_map_width = feature_maps_shape[3]; auto num_rois = rois_shape[0]; - bool aligned = false; - T offset_src = static_cast(0); - T offset_dst = static_cast(0); - switch (aligned_mode) { - case AlignedMode::HALF_PIXEL_FOR_NN: { - aligned = true; - offset_dst = static_cast(-0.5); - break; - } - case AlignedMode::HALF_PIXEL: { - aligned = true; - offset_src = static_cast(0.5); - offset_dst = static_cast(-0.5); - break; - } - case AlignedMode::ASYMMETRIC: { - break; - } - default: { - OPENVINO_THROW(std::string("Not supported aligned_mode")); - break; - } - } + TROIPolicy roi_policy; + roi_policy.init(rois, rois_shape, spatial_scale, aligned_mode, clockwise); for (unsigned int roi_index = 0; roi_index < num_rois; roi_index++) { - // Get ROI`s corners - T x1 = (rois[coordinate_index({roi_index, 0}, rois_shape)] + offset_src) * spatial_scale + offset_dst; - T y1 = (rois[coordinate_index({roi_index, 1}, rois_shape)] + offset_src) * spatial_scale + offset_dst; - T x2 = (rois[coordinate_index({roi_index, 2}, rois_shape)] + offset_src) * spatial_scale + offset_dst; - T y2 = (rois[coordinate_index({roi_index, 3}, rois_shape)] + offset_src) * spatial_scale + offset_dst; + const auto roi_sampling_space = roi_policy.get_sampling_space_for_index(roi_index); - T roi_width = x2 - x1; - T roi_height = y2 - y1; - - if (!aligned) { - roi_width = std::max(roi_width, static_cast(1.0)); - roi_height = std::max(roi_height, static_cast(1.0)); - } + T x1 = roi_sampling_space.get_start_x(); + T y1 = roi_sampling_space.get_start_y(); + T roi_width = roi_sampling_space.get_size_x(); + T roi_height = roi_sampling_space.get_size_y(); T bin_width = roi_width / pooled_width; T bin_height = roi_height / pooled_height; @@ -98,12 +253,18 @@ void roi_align(const T* feature_maps, for (int y_bin_ind = 0; y_bin_ind < pooled_height; y_bin_ind++) { for (int x_bin_ind = 0; x_bin_ind < pooled_width; x_bin_ind++) { for (int y_sample_ind = 0; y_sample_ind < sampling_ratio_y; y_sample_ind++) { - T sample_y = y1 + static_cast(y_bin_ind) * bin_height + - sample_distance_y * (static_cast(y_sample_ind) + static_cast(0.5f)); + T pre_sample_y = y1 + static_cast(y_bin_ind) * bin_height + + sample_distance_y * (static_cast(y_sample_ind) + static_cast(0.5f)); for (int64_t x_sample_ind = 0; x_sample_ind < sampling_ratio_x; x_sample_ind++) { - T sample_x = x1 + static_cast(x_bin_ind) * bin_width + - sample_distance_x * (static_cast(x_sample_ind) + static_cast(0.5f)); + T pre_sample_x = x1 + static_cast(x_bin_ind) * bin_width + + sample_distance_x * (static_cast(x_sample_ind) + static_cast(0.5f)); + + const auto transformed = + roi_sampling_space.transform_sampling_point_to_image_space({pre_sample_x, pre_sample_y}); + + T sample_x = transformed.x; + T sample_y = transformed.y; if (sample_x < -1.0 || sample_x > static_cast(feature_map_width) || sample_y < -1.0 || sample_y > static_cast(feature_map_height)) { diff --git a/src/plugins/template/backend/ops/ops_evaluates.hpp b/src/plugins/template/backend/ops/ops_evaluates.hpp index b4977967f47..180f3698939 100644 --- a/src/plugins/template/backend/ops/ops_evaluates.hpp +++ b/src/plugins/template/backend/ops/ops_evaluates.hpp @@ -489,6 +489,10 @@ extern template bool evaluate_node(std::shared_ptr(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs); + extern template bool evaluate_node(std::shared_ptr node, ov::TensorVector& outputs, const ov::TensorVector& inputs); diff --git a/src/plugins/template/backend/ops/roi_align_rotated.cpp b/src/plugins/template/backend/ops/roi_align_rotated.cpp new file mode 100644 index 00000000000..ec409a73b07 --- /dev/null +++ b/src/plugins/template/backend/ops/roi_align_rotated.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "evaluate_node.hpp" +#include "evaluates_map.hpp" +#include "openvino/op/roi_align.hpp" +#include "openvino/reference/roi_align.hpp" + +template +bool evaluate(const std::shared_ptr& op, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + using T = typename ov::element_type_traits::value_type; + std::vector batch_indices_vec_scaled_up = get_integers(inputs[2], inputs[2].get_shape()); + ov::reference::roi_align( + inputs[0].data(), + inputs[1].data(), + batch_indices_vec_scaled_up.data(), + outputs[0].data(), + op->get_input_shape(0), + op->get_input_shape(1), + op->get_input_shape(2), + op->get_output_shape(0), + op->get_pooled_h(), + op->get_pooled_w(), + op->get_sampling_ratio(), + op->get_spatial_scale(), + ov::op::v3::ROIAlign::PoolingMode::AVG, + ov::op::v9::ROIAlign::AlignedMode::ASYMMETRIC, + op->get_clockwise_mode()); + return true; +} + +template <> +bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + const auto& element_type = node->get_output_element_type(0); + +#define CASE(type) \ + case ov::element::type: \ + return evaluate(ov::as_type_ptr(node), outputs, inputs); + + switch (element_type) { + CASE(bf16); + CASE(f16); + CASE(f32); + CASE(f64); + default: + OPENVINO_THROW("Unhandled data type ", element_type, " in evaluate_node()"); + } +#undef CASE +} diff --git a/src/plugins/template/backend/opset_int_tbl.hpp b/src/plugins/template/backend/opset_int_tbl.hpp index a9c9aa8737b..c6fd3efb7ad 100644 --- a/src/plugins/template/backend/opset_int_tbl.hpp +++ b/src/plugins/template/backend/opset_int_tbl.hpp @@ -162,6 +162,7 @@ _OPENVINO_OP_REG(Multinomial, ov::op::v13) _OPENVINO_OP_REG(Inverse, ov::op::v14) _OPENVINO_OP_REG(AvgPool, ov::op::v14) _OPENVINO_OP_REG(MaxPool, ov::op::v14) +_OPENVINO_OP_REG(ROIAlignRotated, ov::op::v14) _OPENVINO_OP_REG(AUGRUCell, ov::op::internal) _OPENVINO_OP_REG(AUGRUSequence, ov::op::internal) diff --git a/src/plugins/template/tests/functional/op_reference/roi_align_rotated.cpp b/src/plugins/template/tests/functional/op_reference/roi_align_rotated.cpp new file mode 100644 index 00000000000..fa129bb5c8d --- /dev/null +++ b/src/plugins/template/tests/functional/op_reference/roi_align_rotated.cpp @@ -0,0 +1,303 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/roi_align_rotated.hpp" + +#include + +#include "base_reference_test.hpp" +#include "openvino/op/constant.hpp" +#include "openvino/op/parameter.hpp" + +using namespace reference_tests; +using namespace ov; + +namespace { + +constexpr double PI = 3.141592653589793238462643383279; + +struct ROIAlignRotatedParams { + PartialShape inputShape; + int32_t pooledH; + int32_t pooledW; + float spatialScale; + int32_t samplingRatio; + bool clockwise; + std::string testcaseName; + ov::Tensor input; + reference_tests::Tensor rois; + reference_tests::Tensor roiBatchIdxs; + reference_tests::Tensor expectedOutput; +}; + +template +ROIAlignRotatedParams PrepareTestCaseParams(const PartialShape& inputShape, + size_t pooledH, + size_t pooledW, + float spatialScale, + int32_t samplingRatio, + bool clockwise, + const std::vector& inputValues, + const std::vector& roisVals, + const std::vector& roiBatchIdx, + const std::vector& expectedValues, + const std::string& testcaseName) { + ROIAlignRotatedParams ret; + + constexpr size_t rois_second_dim_size = 5; //< By definition of the ROIAlignRotated op + + const auto numOfRois = roisVals.size() / rois_second_dim_size; + const auto channels = static_cast(inputShape[1].get_length()); + const auto elementType = element::from(); + + ret.inputShape = inputShape; + ret.pooledH = pooledH; + ret.pooledW = pooledW; + ret.spatialScale = spatialScale; + ret.samplingRatio = samplingRatio; + ret.clockwise = clockwise; + ret.testcaseName = testcaseName; + ret.input = CreateTensor(elementType, inputValues); + ret.rois = reference_tests::Tensor(elementType, {numOfRois, 5}, roisVals); + ret.roiBatchIdxs = reference_tests::Tensor(element::Type_t::i32, {numOfRois}, roiBatchIdx); + ret.expectedOutput = reference_tests::Tensor(elementType, {numOfRois, channels, pooledH, pooledW}, expectedValues); + + return ret; +} + +class ReferenceROIAlignRotatedTest : public testing::TestWithParam, public CommonReferenceTest { +public: + void SetUp() override { + auto params = GetParam(); + function = CreateFunction(params); + inputData = {params.input}; + refOutData = {params.expectedOutput.data}; + } + + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + auto param = obj.param; + std::ostringstream result; + result << "type=" << param.input.get_element_type(); + result << "_inputShape=" << param.inputShape; + result << "_pooledH=" << param.pooledH; + result << "_pooledW=" << param.pooledW; + result << "_spatialScale=" << param.spatialScale; + result << "_samplingRatio=" << param.samplingRatio; + result << "_clockwise=" << param.clockwise; + result << "_roisShape=" << param.rois.shape; + result << "_roisBatchIdxShape=" << param.roiBatchIdxs.shape; + result << "_outputShape=" << param.expectedOutput.shape; + if (!param.testcaseName.empty()) { + result << "_=" << param.testcaseName; + } + return result.str(); + } + +private: + static std::shared_ptr CreateFunction(const ROIAlignRotatedParams& params) { + const auto featureMap = std::make_shared(params.input.get_element_type(), params.inputShape); + const auto coords = + std::make_shared(params.rois.type, params.rois.shape, params.rois.data.data()); + const auto roisIdx = std::make_shared(params.roiBatchIdxs.type, + params.roiBatchIdxs.shape, + params.roiBatchIdxs.data.data()); + const auto roi_align_rot = std::make_shared(featureMap, + coords, + roisIdx, + params.pooledH, + params.pooledW, + params.samplingRatio, + params.spatialScale, + params.clockwise); + return std::make_shared(NodeVector{roi_align_rot}, ParameterVector{featureMap}); + } +}; + +TEST_P(ReferenceROIAlignRotatedTest, CompareWithRefs) { + Exec(); +} + +template +std::vector generateParams() { + using T = typename element_type_traits::value_type; + std::vector params; + // NOTE: expected output were generated using mmvc roi_align_rotated implementation. + params.push_back(PrepareTestCaseParams( + {2, 1, 8, 8}, + 2, + 2, + 1.0f, + 2, + true, + {0, 1, 8, 5, 5, 2, 0, 7, 7, 10, 4, 5, 9, 0, 0, 5, 7, 0, 4, 0, 4, 7, 6, 10, 9, 5, 1, 7, 4, 7, 10, 8, + 2, 0, 8, 3, 6, 8, 10, 4, 2, 10, 7, 8, 7, 0, 6, 9, 2, 4, 8, 5, 2, 3, 3, 1, 5, 9, 10, 0, 9, 5, 5, 3, + 10, 5, 2, 0, 10, 0, 5, 4, 3, 10, 5, 5, 10, 0, 8, 8, 9, 1, 0, 7, 9, 6, 8, 7, 10, 9, 2, 3, 3, 5, 6, 9, + 4, 9, 2, 4, 5, 5, 3, 1, 1, 6, 8, 0, 5, 5, 10, 8, 6, 9, 6, 9, 1, 2, 7, 1, 1, 3, 0, 4, 0, 7, 10, 2}, + {3.5, 3.5, 2, 2, 0, 3.5, 3.5, 2, 2, 0}, + {0, 1}, + {3, 3.75, 4.75, 5, 3, 5.5, 2.75, 3.75}, + "roi_align_rotated_angle_0")); + params.push_back(PrepareTestCaseParams({1, 1, 2, 2}, + 2, + 2, + 1.0f, + 2, + true, + {1, 2, 3, 4}, + {0.5, 0.5, 1, 1, 0}, + {0}, + {1.0, 1.25, 1.5, 1.75}, + "roi_align_rotated_simple_angle_0")); + params.push_back(PrepareTestCaseParams({1, 1, 2, 2}, + 2, + 2, + 1.0f, + 2, + false, + {1, 2, 3, 4}, + {0.5, 0.5, 1, 1, PI / 2}, + {0}, + {1.5, 1.0, 1.75, 1.25}, + "roi_align_rotated_simple_angle_PI/2")); + params.push_back(PrepareTestCaseParams({1, 1, 2, 2}, + 2, + 2, + 1.0f, + 2, + false, + {1, 2, 3, 4}, + {0.5, 0.5, 1, 1, PI, 0.5, 0.5, 1, 1, 2 * PI}, + {0, 0}, + {1.75, 1.5, 1.25, 1.0, 1.0, 1.25, 1.5, 1.75}, + "roi_align_rotated_batch_idx_test")); + params.push_back(PrepareTestCaseParams({1, 2, 2, 2}, + 2, + 2, + 1.0f, + 2, + false, + {1, 2, 3, 4, 4, 3, 2, 1}, + {0.5, 0.5, 1, 1, 0}, + {0}, + {1.0, 1.25, 1.5, 1.75, 4.0, 3.75, 3.5, 3.25}, + "roi_align_rotated_channels_test")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 3, + 1, + 1.0f, + 2, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {1, 1, 4, 4, 0}, + {0}, + {0.8750, 4.2500, 10.9167}, + "roi_align_rotated_box_outside_feature_map_top_left")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 3, + 1, + 1.0f, + 2, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {1, 1, 4, 4, PI / 4}, + {0}, + {2.6107, 4.6642, 6.8819}, + "roi_align_rotated_box_outside_feature_map_top_left_angle_PI/4")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 3, + 1, + 1.0f, + 2, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {5, 5, 4, 4, 0}, + {0}, + {10.1667, 12.2500, 0.0}, + "roi_align_rotated_box_outside_feature_map_bottom_right_angle_0")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 3, + 1, + 1.0f, + 2, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {5, 5, 1, 5, PI / 4}, + {0}, + {0.0, 25.0, 0.0}, + "roi_align_rotated_box_outside_feature_map_bottom_right_angle_PI/4")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 2, + 2, + 1.0f, + 0, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {3, 3, 4, 4, 0}, + {0}, + {10.0, 12.0, 20.0, 22.0}, + "roi_align_rotated_box_outside_sampling_ratio_auto")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 2, + 2, + 0.25f, + 0, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {3, 3, 4, 4, 0}, + {0}, + {1.0, 1.5, 3.5, 4.0}, + "roi_align_rotated_box_outside_sampling_ratio_auto_scale_0.25")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 2, + 2, + 2.0f, + 0, + true, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {3, 3, 4, 4, 0}, + {0}, + {20.5, 0.0, 0.0, 0.0}, + "roi_align_rotated_box_outside_sampling_ratio_auto_scale_2")); + params.push_back(PrepareTestCaseParams( + {1, 1, 5, 5}, + 5, + 2, + 0.78f, + 0, + false, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}, + {3, 1, 4, 2, PI / 3}, + {0}, + {5.1271, 1.2473, 6.1773, 2.9598, 7.2275, 3.2300, 8.2777, 3.7458, 9.3279, 4.4060}, + "roi_align_rotated_all_features")); + return params; +} + +std::vector generateCombinedParams() { + const std::vector> generatedParams{ + generateParams(), + generateParams(), + generateParams(), + generateParams(), + }; + std::vector combinedParams; + + for (const auto& params : generatedParams) { + combinedParams.insert(combinedParams.end(), params.begin(), params.end()); + } + return combinedParams; +} + +INSTANTIATE_TEST_SUITE_P(smoke_ROIAlignRotated_With_Hardcoded_Refs, + ReferenceROIAlignRotatedTest, + testing::ValuesIn(generateCombinedParams()), + ReferenceROIAlignRotatedTest::getTestCaseName); +} // namespace