Skip to content

Commit 6e05cea

Browse files
authored
[OV20] Reference implementation for NV12toRGB and NV12toBGR operations (openvinotoolkit#7601)
* Reference implementation for NV12toRGB and NV12toBGR operations Tests: - ngraph: visitor + type_prop - template plugin: reference implementation - inference-engine: shared tests for plugins - cpu plugin: compare with ref implementation tests * Fix clang * Serialization tests * Fix clang-format * Changed 'f32' to 'any supported floating-point type' Added appropriate shape inference tests Added error test for >2 inputs Fixed failed CI tests * Updates after rebase + Try to fix Ninja build * Fix CI * Support endianness + potential fix of win32 test fails * Fix review comment * Fix review comments * Fix unit test build * Fix unit test build #2 * Possible build fix 3 * Simplified reference tests Observed issue with shuffling Y pixels on little-endian systems, added tests
1 parent b339bb7 commit 6e05cea

File tree

23 files changed

+1295
-1
lines changed

23 files changed

+1295
-1
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include <gtest/gtest.h>
6+
7+
#include <openvino/core/function.hpp>
8+
#include <tuple>
9+
#include <openvino/op/nv12_to_rgb.hpp>
10+
#include <openvino/op/nv12_to_bgr.hpp>
11+
12+
#include "base_reference_test.hpp"
13+
14+
using namespace ov;
15+
using namespace InferenceEngine;
16+
using namespace reference_tests;
17+
18+
class ReferenceConvertColorNV12LayerTest : public testing::Test, public CommonReferenceTest {
19+
public:
20+
void SetUp() override {
21+
}
22+
23+
public:
24+
template <typename T>
25+
static std::shared_ptr<Function> CreateFunction(const Tensor& input) {
26+
const auto in = std::make_shared<op::v0::Parameter>(input.type, input.shape);
27+
std::shared_ptr<Node> conv;
28+
conv = std::make_shared<T>(in);
29+
auto res = std::make_shared<op::v0::Result>(conv);
30+
return std::make_shared<Function>(ResultVector{res}, ParameterVector {in});
31+
}
32+
33+
template <typename T>
34+
static std::shared_ptr<Function> CreateFunction2(const Tensor& input1, const Tensor& input2) {
35+
const auto in1 = std::make_shared<op::v0::Parameter>(input1.type, input1.shape);
36+
const auto in2 = std::make_shared<op::v0::Parameter>(input2.type, input2.shape);
37+
std::shared_ptr<Node> conv;
38+
conv = std::make_shared<T>(in1, in2);
39+
auto res = std::make_shared<op::v0::Result>(conv);
40+
return std::make_shared<Function>(ResultVector{res}, ParameterVector {in1, in2});
41+
}
42+
};
43+
44+
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_r_u8_single_rgb) {
45+
auto input = std::vector<uint8_t> {0x51, 0x51, 0x51, 0x51, 0xf0, 0x5a};
46+
auto input_shape = Shape{1, 3, 2, 1};
47+
auto exp_out = std::vector<uint8_t> {0xff, 0, 0, 0xff, 0, 0, 0xff, 0, 0, 0xff, 0, 0};
48+
auto out_shape = Shape{1, 2, 2, 3};
49+
Tensor inp_tensor(input_shape, element::u8, input);
50+
inputData = {inp_tensor.data};
51+
function = CreateFunction<op::v8::NV12toRGB>(inp_tensor);
52+
Tensor exp_tensor_u8(out_shape, element::u8, exp_out);
53+
refOutData = {exp_tensor_u8.data};
54+
Exec();
55+
}
56+
57+
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_color_u8_single_bgr) {
58+
auto input = std::vector<uint8_t> {0xeb, 0x51, 0xeb, 0x51, 0xb8, 0x6d};
59+
auto input_shape = Shape{1, 3, 2, 1};
60+
auto exp_out = std::vector<uint8_t> {37, 37, 164, 215, 216, 255, 37, 37, 164, 215, 216, 255};
61+
auto out_shape = Shape{1, 2, 2, 3};
62+
63+
Tensor inp_tensor(input_shape, element::u8, input);
64+
inputData = {inp_tensor.data};
65+
66+
Tensor exp_tensor_u8(out_shape, element::u8, exp_out);
67+
refOutData = {exp_tensor_u8.data};
68+
69+
function = CreateFunction<op::v8::NV12toBGR>(inp_tensor);
70+
71+
Exec();
72+
}
73+
74+
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_g_fp32_single_rgb) {
75+
threshold = 2.f;
76+
auto input = std::vector<float> {145.f, 145.f, 145.f, 145.f, 34.f, 54.f};
77+
auto input_shape = Shape{1, 3, 2, 1};
78+
auto exp_out = std::vector<float> {0, 255.f, 0, 0, 255.f, 0, 0, 255.f, 0, 0, 255.f, 0};
79+
auto out_shape = Shape{1, 2, 2, 3};
80+
81+
Tensor inp_tensor(input_shape, element::f32, input);
82+
inputData = {inp_tensor.data};
83+
84+
Tensor exp_tensor(out_shape, element::f32, exp_out);
85+
refOutData = {exp_tensor.data};
86+
87+
function = CreateFunction<op::v8::NV12toRGB>(inp_tensor);
88+
89+
Exec();
90+
}
91+
92+
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_batch_fp32_two_bgr) {
93+
threshold = 2.f;
94+
auto input_y = std::vector<float> {81.f, 81.f, 81.f, 81.f,
95+
145.f, 145.f, 145.f, 145.f,
96+
41.f, 41.f, 41.f, 41.f};
97+
auto input_shape_y = Shape{3, 2, 2, 1};
98+
99+
auto input_uv = std::vector<float> {240., 90.,
100+
34., 54.,
101+
110., 240.};
102+
auto input_shape_uv = Shape{3, 1, 1, 2};
103+
104+
auto exp_out = std::vector<float> {0, 0, 255., 0, 0, 255., 0, 0, 255., 0, 0, 255.,
105+
0, 255., 0, 0, 255., 0, 0, 255., 0, 0, 255., 0,
106+
255., 0, 0, 255., 0, 0, 255., 0, 0, 255., 0, 0};
107+
auto out_shape = Shape{3, 2, 2, 3};
108+
109+
Tensor inp_tensor_y(input_shape_y, element::f32, input_y);
110+
Tensor inp_tensor_uv(input_shape_uv, element::f32, input_uv);
111+
inputData = {inp_tensor_y.data, inp_tensor_uv.data};
112+
113+
Tensor exp_tensor(out_shape, element::f32, exp_out);
114+
refOutData = {exp_tensor.data};
115+
116+
function = CreateFunction2<op::v8::NV12toBGR>(inp_tensor_y, inp_tensor_uv);
117+
118+
Exec();
119+
}
120+
121+
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_color2x2_f32_two_rgb) {
122+
threshold = 2.f;
123+
auto input_y = std::vector<float> {235, 81, 235, 81};
124+
auto input_shape_y = Shape{1, 2, 2, 1};
125+
126+
auto input_uv = std::vector<float> {184, 109};
127+
auto input_shape_uv = Shape{1, 1, 1, 2};
128+
129+
auto exp_out = std::vector<float> {164, 37, 37, 216, 215, 255, 164, 37, 37, 216, 215, 255};
130+
auto out_shape = Shape{1, 2, 2, 3};
131+
132+
Tensor inp_tensor_y(input_shape_y, element::f32, input_y);
133+
Tensor inp_tensor_uv(input_shape_uv, element::f32, input_uv);
134+
inputData = {inp_tensor_y.data, inp_tensor_uv.data};
135+
136+
Tensor exp_tensor(out_shape, element::f32, exp_out);
137+
refOutData = {exp_tensor.data};
138+
139+
function = CreateFunction2<op::v8::NV12toRGB>(inp_tensor_y, inp_tensor_uv);
140+
141+
Exec();
142+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "shared_test_classes/single_layer/convert_color_nv12.hpp"
6+
7+
using namespace LayerTestsDefinitions;
8+
9+
namespace {
10+
11+
TEST_P(ConvertColorNV12LayerTest, Serialize) {
12+
Serialize();
13+
}
14+
15+
const std::vector<ov::Shape> inShapes_nhwc = {
16+
{1, 10, 10, 1}
17+
};
18+
19+
const std::vector<ov::element::Type> inTypes = {
20+
ov::element::u8, ov::element::f32
21+
};
22+
23+
const auto testCase_values = ::testing::Combine(
24+
::testing::ValuesIn(inShapes_nhwc),
25+
::testing::ValuesIn(inTypes),
26+
::testing::Bool(),
27+
::testing::Bool(),
28+
::testing::Values(CommonTestUtils::DEVICE_CPU)
29+
);
30+
31+
INSTANTIATE_TEST_SUITE_P(smoke_CompareWithRefs, ConvertColorNV12LayerTest, testCase_values, ConvertColorNV12LayerTest::getTestCaseName);
32+
33+
} // namespace
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include <vector>
6+
7+
#include "single_layer_tests/convert_color_nv12.hpp"
8+
#include "common_test_utils/test_constants.hpp"
9+
10+
using namespace LayerTestsDefinitions;
11+
12+
namespace {
13+
14+
const std::vector<ov::Shape> inShapes_nhwc = {
15+
{1, 10, 10, 1}
16+
};
17+
18+
const std::vector<ov::element::Type> inTypes = {
19+
ov::element::u8, ov::element::f32
20+
};
21+
22+
const auto testCase_values = ::testing::Combine(
23+
::testing::ValuesIn(inShapes_nhwc),
24+
::testing::ValuesIn(inTypes),
25+
::testing::Bool(),
26+
::testing::Bool(),
27+
::testing::Values(CommonTestUtils::DEVICE_CPU)
28+
);
29+
30+
31+
INSTANTIATE_TEST_SUITE_P(smoke_TestsConvertColorNV12, ConvertColorNV12LayerTest, testCase_values, ConvertColorNV12LayerTest::getTestCaseName);
32+
33+
} // namespace
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include "shared_test_classes/single_layer/convert_color_nv12.hpp"
8+
9+
namespace LayerTestsDefinitions {
10+
11+
TEST_P(ConvertColorNV12LayerTest, CompareWithRefs) {
12+
Run();
13+
};
14+
15+
} // namespace LayerTestsDefinitions
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include <tuple>
8+
#include <string>
9+
#include <vector>
10+
11+
#include "shared_test_classes/base/layer_test_utils.hpp"
12+
#include "ngraph_functions/builders.hpp"
13+
#include "ngraph_functions/utils/ngraph_helpers.hpp"
14+
15+
namespace LayerTestsDefinitions {
16+
17+
using ConvertColorNV12ParamsTuple = std::tuple<
18+
ov::Shape, // Input Shape
19+
ov::element::Type, // Element type
20+
bool, // Conversion type
21+
bool, // 1 or 2 planes
22+
std::string>; // Device name
23+
24+
class ConvertColorNV12LayerTest : public testing::WithParamInterface<ConvertColorNV12ParamsTuple>,
25+
virtual public LayerTestsUtils::LayerTestsCommon {
26+
public:
27+
static std::string getTestCaseName(const testing::TestParamInfo<ConvertColorNV12ParamsTuple> &obj);
28+
29+
protected:
30+
void SetUp() override;
31+
};
32+
33+
} // namespace LayerTestsDefinitions
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "shared_test_classes/single_layer/convert_color_nv12.hpp"
6+
#include "openvino/op/nv12_to_rgb.hpp"
7+
#include "openvino/op/nv12_to_bgr.hpp"
8+
9+
namespace LayerTestsDefinitions {
10+
11+
std::string ConvertColorNV12LayerTest::getTestCaseName(const testing::TestParamInfo<ConvertColorNV12ParamsTuple> &obj) {
12+
ov::Shape inputShape;
13+
ov::element::Type type;
14+
bool conversion, singlePlane;
15+
std::string targetName;
16+
std::tie(inputShape, type, conversion, singlePlane, targetName) = obj.param;
17+
std::ostringstream result;
18+
result << "IS=" << CommonTestUtils::vec2str(inputShape) << "_";
19+
result << "netPRC=" << type.c_type_string() << "_";
20+
result << "convRGB=" << conversion << "_";
21+
result << "singlePlane=" << singlePlane << "_";
22+
result << "targetDevice=" << targetName;
23+
return result.str();
24+
}
25+
26+
void ConvertColorNV12LayerTest::SetUp() {
27+
ov::Shape inputShape;
28+
ov::element::Type ngPrc;
29+
bool conversionToRGB, singlePlane;
30+
threshold = 2.0f; // NV12 color conversion can use various of algorithms, thus some deviation is allowed
31+
std::tie(inputShape, ngPrc, conversionToRGB, singlePlane, targetDevice) = GetParam();
32+
if (singlePlane) {
33+
inputShape[1] = inputShape[1] * 3 / 2;
34+
auto param = std::make_shared<ov::op::v0::Parameter>(ngPrc, inputShape);
35+
std::shared_ptr<ov::Node> convert_color;
36+
if (conversionToRGB) {
37+
convert_color = std::make_shared<ov::op::v8::NV12toRGB>(param);
38+
} else {
39+
convert_color = std::make_shared<ov::op::v8::NV12toBGR>(param);
40+
}
41+
function = std::make_shared<ov::Function>(std::make_shared<ov::op::v0::Result>(convert_color),
42+
ov::ParameterVector{param}, "ConvertColorNV12");
43+
} else {
44+
auto uvShape = ov::Shape{inputShape[0], inputShape[1] / 2, inputShape[2] / 2, 2};
45+
auto param_y = std::make_shared<ov::op::v0::Parameter>(ngPrc, inputShape);
46+
auto param_uv = std::make_shared<ov::op::v0::Parameter>(ngPrc, uvShape);
47+
std::shared_ptr<ov::Node> convert_color;
48+
if (conversionToRGB) {
49+
convert_color = std::make_shared<ov::op::v8::NV12toRGB>(param_y, param_uv);
50+
} else {
51+
convert_color = std::make_shared<ov::op::v8::NV12toBGR>(param_y, param_uv);
52+
}
53+
function = std::make_shared<ov::Function>(std::make_shared<ov::op::v0::Result>(convert_color),
54+
ov::ParameterVector{param_y, param_uv}, "ConvertColorNV12");
55+
}
56+
}
57+
58+
} // namespace LayerTestsDefinitions
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include "openvino/op/nv12_to_bgr.hpp"
8+
9+
namespace ngraph {
10+
namespace op {
11+
namespace v8 {
12+
using ov::op::v8::NV12toBGR;
13+
} // namespace v8
14+
} // namespace op
15+
} // namespace ngraph
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (C) 2018-2021 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#pragma once
6+
7+
#include "openvino/op/nv12_to_rgb.hpp"
8+
9+
namespace ngraph {
10+
namespace op {
11+
namespace v8 {
12+
using ov::op::v8::NV12toRGB;
13+
} // namespace v8
14+
} // namespace op
15+
} // namespace ngraph

ngraph/core/include/ngraph/ops.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
#include "ngraph/op/normalize_l2.hpp"
104104
#include "ngraph/op/not.hpp"
105105
#include "ngraph/op/not_equal.hpp"
106+
#include "ngraph/op/nv12_to_bgr.hpp"
107+
#include "ngraph/op/nv12_to_rgb.hpp"
106108
#include "ngraph/op/one_hot.hpp"
107109
#include "ngraph/op/or.hpp"
108110
#include "ngraph/op/pad.hpp"

0 commit comments

Comments
 (0)