1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Alekhin
2022-02-22 19:33:07 +00:00
256 changed files with 10503 additions and 5119 deletions
@@ -1701,6 +1701,25 @@ namespace {
};
};
namespace {
class TestMediaGray final : public cv::MediaFrame::IAdapter {
cv::Mat m_mat;
public:
explicit TestMediaGray(cv::Mat m)
: m_mat(m) {
}
cv::GFrameDesc meta() const override {
return cv::GFrameDesc{ cv::MediaFormat::GRAY, cv::Size(m_mat.cols, m_mat.rows) };
}
cv::MediaFrame::View access(cv::MediaFrame::Access) override {
cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
return cv::MediaFrame::View(std::move(pp), std::move(ss));
}
};
};
TEST_P(SizeMFTest, ParseTest)
{
cv::Size out_sz;
@@ -1715,6 +1734,20 @@ TEST_P(SizeMFTest, ParseTest)
EXPECT_EQ(sz, out_sz);
}
TEST_P(SizeMFTest, ParseGrayTest)
{
cv::Size out_sz;
cv::Mat gray = cv::Mat::eye(sz.height, sz.width, CV_8UC1);
cv::MediaFrame frame = cv::MediaFrame::Create<TestMediaGray>(gray);
cv::GFrame in;
auto out = cv::gapi::streaming::size(in);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
c.apply(cv::gin(frame), cv::gout(out_sz), getCompileArgs());
EXPECT_EQ(sz, out_sz);
}
} // opencv_test
#endif //OPENCV_GAPI_CORE_TESTS_INL_HPP
+80
View File
@@ -29,6 +29,23 @@ GAPI_OCV_KERNEL(OCVBlurFrame, GBlurFrame) {
}
};
G_API_OP(GBlurFrameGray, <GMat(GFrame)>, "test.blur_frame_gray") {
static GMatDesc outMeta(GFrameDesc in) {
return cv::GMatDesc(CV_8U, 1, in.size);
}
};
GAPI_OCV_KERNEL(OCVBlurFrameGray, GBlurFrameGray) {
static void run(const cv::MediaFrame & in, cv::Mat & out) {
GAPI_Assert(in.desc().fmt == cv::MediaFormat::GRAY);
cv::MediaFrame::View view = in.access(cv::MediaFrame::Access::R);
cv::blur(cv::Mat(in.desc().size, CV_8UC1, view.ptr[0], view.stride[0]),
out,
cv::Size{ 3,3 });
}
};
////////////////////////////////////////////////////////////////////////////////
// cv::MediaFrame tests
namespace {
@@ -70,6 +87,26 @@ public:
return cv::MediaFrame::View(std::move(pp), std::move(ss));
}
};
class TestMediaGray final : public cv::MediaFrame::IAdapter {
cv::Mat m_mat;
using Cb = cv::MediaFrame::View::Callback;
Cb m_cb;
public:
explicit TestMediaGray(cv::Mat m, Cb cb = []() {})
: m_mat(m), m_cb(cb) {
}
cv::GFrameDesc meta() const override {
return cv::GFrameDesc{ cv::MediaFormat::GRAY, cv::Size(m_mat.cols, m_mat.rows) };
}
cv::MediaFrame::View access(cv::MediaFrame::Access) override {
cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{ m_cb });
}
};
} // anonymous namespace
struct MediaFrame_Test: public ::testing::Test {
@@ -120,6 +157,49 @@ TEST_F(MediaFrame_BGR, Input) {
EXPECT_EQ(0, cvtest::norm(out_mat_ocv, out_mat_gapi, NORM_INF));
}
struct MediaFrame_Gray : public MediaFrame_Test {
M gray;
MediaFrame_Gray()
: gray(M::eye(240, 320, CV_8UC1)) {
cv::randn(gray, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
frame = MF::Create<TestMediaGray>(gray);
}
};
TEST_F(MediaFrame_Gray, Meta) {
auto meta = frame.desc();
EXPECT_EQ(cv::MediaFormat::GRAY, meta.fmt);
EXPECT_EQ(cv::Size(320, 240), meta.size);
}
TEST_F(MediaFrame_Gray, Access) {
cv::MediaFrame::View view1 = frame.access(cv::MediaFrame::Access::R);
EXPECT_EQ(gray.ptr(), view1.ptr[0]);
EXPECT_EQ(gray.step, view1.stride[0]);
cv::MediaFrame::View view2 = frame.access(cv::MediaFrame::Access::R);
EXPECT_EQ(gray.ptr(), view2.ptr[0]);
EXPECT_EQ(gray.step, view2.stride[0]);
}
TEST_F(MediaFrame_Gray, Input) {
// Run the OpenCV code
cv::Mat out_mat_ocv, out_mat_gapi;
cv::blur(gray, out_mat_ocv, cv::Size{ 3,3 });
// Run the G-API code
cv::GFrame in;
cv::GMat out = GBlurFrameGray::on(in);
cv::GComputation(cv::GIn(in), cv::GOut(out))
.apply(cv::gin(frame),
cv::gout(out_mat_gapi),
cv::compile_args(cv::gapi::kernels<OCVBlurFrameGray>()));
// Compare
EXPECT_EQ(0, cvtest::norm(out_mat_ocv, out_mat_gapi, NORM_INF));
}
struct MediaFrame_NV12: public MediaFrame_Test {
cv::Size sz;
cv::Mat buf, y, uv;
@@ -29,6 +29,10 @@
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4100)
# if _MSC_VER < 1910
# pragma warning(disable:4268) // Disable warnings of ngraph. OpenVINO recommends to use MSVS 2019.
# pragma warning(disable:4800)
# endif
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
+26
View File
@@ -0,0 +1,26 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2021 Intel Corporation
#include "../test_precomp.hpp"
#ifdef HAVE_OAK
#include <opencv2/gapi/oak/oak.hpp>
namespace opencv_test
{
// FIXME: consider a better solution
TEST(OAK, Available)
{
cv::GFrame in;
auto out = cv::gapi::oak::encode(in, {});
auto args = cv::compile_args(cv::gapi::oak::ColorCameraParams{}, cv::gapi::oak::kernels());
auto pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out)).compileStreaming(std::move(args));
}
} // opencv_test
#endif // HAVE_OAK
@@ -29,6 +29,7 @@ namespace opencv_test
struct GStreamerSourceTest : public TestWithParam<std::tuple<std::string, cv::Size, std::size_t>>
{ };
TEST_P(GStreamerSourceTest, AccuracyTest)
{
std::string pipeline;
@@ -143,6 +144,16 @@ G_TYPED_KERNEL(GGstFrameCopyToNV12, <std::tuple<cv::GMat,cv::GMat>(GFrame)>,
}
};
G_TYPED_KERNEL(GGstFrameCopyToGRAY8, <cv::GMat(GFrame)>,
"org.opencv.test.gstframe_copy_to_gray8")
{
static GMatDesc outMeta(GFrameDesc desc) {
GMatDesc y{ CV_8U, 1, desc.size, false };
return y;
}
};
GAPI_OCV_KERNEL(GOCVGstFrameCopyToNV12, GGstFrameCopyToNV12)
{
static void run(const cv::MediaFrame& in, cv::Mat& y, cv::Mat& uv)
@@ -156,21 +167,50 @@ GAPI_OCV_KERNEL(GOCVGstFrameCopyToNV12, GGstFrameCopyToNV12)
}
};
GAPI_OCV_KERNEL(GOCVGstFrameCopyToGRAY8, GGstFrameCopyToGRAY8)
{
static void run(const cv::MediaFrame & in, cv::Mat & y)
{
auto view = in.access(cv::MediaFrame::Access::R);
cv::Mat ly(y.size(), y.type(), view.ptr[0], view.stride[0]);
ly.copyTo(y);
}
};
TEST_P(GStreamerSourceTest, GFrameTest)
{
std::string pipeline;
cv::Size expectedFrameSize;
std::size_t streamLength { };
bool isNV12 = false;
std::tie(pipeline, expectedFrameSize, streamLength) = GetParam();
//Check if pipline string contains NV12 sub-string
if (pipeline.find("NV12") != std::string::npos) {
isNV12 = true;
}
// Graph declaration:
cv::GFrame in;
cv::GMat copiedY, copiedUV;
std::tie(copiedY, copiedUV) = GGstFrameCopyToNV12::on(in);
cv::GComputation c(cv::GIn(in), cv::GOut(copiedY, copiedUV));
if (isNV12) {
std::tie(copiedY, copiedUV) = GGstFrameCopyToNV12::on(in);
}
else {
copiedY = GGstFrameCopyToGRAY8::on(in);
}
cv::GComputation c(cv::GIn(in), isNV12 ? cv::GOut(copiedY, copiedUV) : cv::GOut(copiedY));
// Graph compilation for streaming mode:
auto ccomp = c.compileStreaming(cv::compile_args(cv::gapi::kernels<GOCVGstFrameCopyToNV12>()));
cv::GStreamingCompiled ccomp;
if (isNV12) {
ccomp = c.compileStreaming(cv::compile_args(cv::gapi::kernels<GOCVGstFrameCopyToNV12>()));
} else {
ccomp = c.compileStreaming(cv::compile_args(cv::gapi::kernels<GOCVGstFrameCopyToGRAY8>()));
}
EXPECT_TRUE(ccomp);
EXPECT_FALSE(ccomp.running());
@@ -186,29 +226,41 @@ TEST_P(GStreamerSourceTest, GFrameTest)
// Streaming - pulling of frames until the end:
cv::Mat y_mat, uv_mat;
EXPECT_TRUE(ccomp.pull(cv::gout(y_mat, uv_mat)));
EXPECT_TRUE(isNV12 ? ccomp.pull(cv::gout(y_mat, uv_mat)) : ccomp.pull(cv::gout(y_mat)));
EXPECT_TRUE(!y_mat.empty());
EXPECT_TRUE(!uv_mat.empty());
if (isNV12) {
EXPECT_TRUE(!uv_mat.empty());
}
cv::Size expectedYSize = expectedFrameSize;
cv::Size expectedUVSize = expectedFrameSize / 2;
EXPECT_EQ(expectedYSize, y_mat.size());
EXPECT_EQ(expectedUVSize, uv_mat.size());
if (isNV12) {
EXPECT_EQ(expectedUVSize, uv_mat.size());
}
EXPECT_EQ(CV_8UC1, y_mat.type());
EXPECT_EQ(CV_8UC2, uv_mat.type());
if (isNV12) {
EXPECT_EQ(CV_8UC2, uv_mat.type());
}
std::size_t framesCount = 1UL;
while (ccomp.pull(cv::gout(y_mat, uv_mat))) {
while (isNV12 ? ccomp.pull(cv::gout(y_mat, uv_mat)) : ccomp.pull(cv::gout(y_mat))) {
EXPECT_TRUE(!y_mat.empty());
EXPECT_TRUE(!uv_mat.empty());
if (isNV12) {
EXPECT_TRUE(!uv_mat.empty());
}
EXPECT_EQ(expectedYSize, y_mat.size());
EXPECT_EQ(expectedUVSize, uv_mat.size());
if (isNV12) {
EXPECT_EQ(expectedUVSize, uv_mat.size());
}
EXPECT_EQ(CV_8UC1, y_mat.type());
EXPECT_EQ(CV_8UC2, uv_mat.type());
if (isNV12) {
EXPECT_EQ(CV_8UC2, uv_mat.type());
}
framesCount++;
}
@@ -221,36 +273,56 @@ TEST_P(GStreamerSourceTest, GFrameTest)
EXPECT_EQ(streamLength, framesCount);
}
// FIXME: Need to launch with sudo. May be infrastructure problems.
// TODO: It is needed to add tests for streaming from native KMB camera: kmbcamsrc
// GStreamer element.
INSTANTIATE_TEST_CASE_P(CameraEmulatingPipeline, GStreamerSourceTest,
Combine(Values("videotestsrc is-live=true pattern=colors num-buffers=10 ! "
"videorate ! videoscale ! "
"video/x-raw,width=1920,height=1080,framerate=3/1 ! "
"video/x-raw,format=NV12,width=1920,height=1080,framerate=3/1 ! "
"appsink",
"videotestsrc is-live=true pattern=colors num-buffers=10 ! "
"videorate ! videoscale ! "
"video/x-raw,format=GRAY8,width=1920,height=1080,framerate=3/1 ! "
"appsink"),
Values(cv::Size(1920, 1080)),
Values(10UL)));
INSTANTIATE_TEST_CASE_P(FileEmulatingPipeline, GStreamerSourceTest,
Combine(Values("videotestsrc pattern=colors num-buffers=10 ! "
"videorate ! videoscale ! "
"video/x-raw,width=640,height=420,framerate=3/1 ! "
"video/x-raw,format=NV12,width=640,height=420,framerate=3/1 ! "
"appsink",
"videotestsrc pattern=colors num-buffers=10 ! "
"videorate ! videoscale ! "
"video/x-raw,format=GRAY8,width=640,height=420,framerate=3/1 ! "
"appsink"),
Values(cv::Size(640, 420)),
Values(10UL)));
INSTANTIATE_TEST_CASE_P(MultipleLiveSources, GStreamerSourceTest,
Combine(Values("videotestsrc is-live=true pattern=colors num-buffers=10 ! "
"videoscale ! video/x-raw,width=1280,height=720 ! appsink "
"videoscale ! video/x-raw,format=NV12,width=1280,height=720 ! appsink "
"videotestsrc is-live=true pattern=colors num-buffers=10 ! "
"fakesink",
"videotestsrc is-live=true pattern=colors num-buffers=10 ! "
"videoscale ! video/x-raw,format=GRAY8,width=1280,height=720 ! appsink "
"videotestsrc is-live=true pattern=colors num-buffers=10 ! "
"fakesink"),
Values(cv::Size(1280, 720)),
Values(10UL)));
INSTANTIATE_TEST_CASE_P(MultipleNotLiveSources, GStreamerSourceTest,
Combine(Values("videotestsrc pattern=colors num-buffers=10 ! "
"videoscale ! video/x-raw,width=1280,height=720 ! appsink "
"videoscale ! video/x-raw,format=NV12,width=1280,height=720 ! appsink "
"videotestsrc pattern=colors num-buffers=10 ! "
"fakesink",
"videotestsrc pattern=colors num-buffers=10 ! "
"videoscale ! video/x-raw,format=GRAY8,width=1280,height=720 ! appsink "
"videotestsrc pattern=colors num-buffers=10 ! "
"fakesink"),
Values(cv::Size(1280, 720)),
@@ -308,11 +380,11 @@ TEST(GStreamerMultiSourceSmokeTest, Test)
EXPECT_FALSE(ccomp.running());
}
struct GStreamerMultiSourceTest :
struct GStreamerMultiSourceTestNV12 :
public TestWithParam<std::tuple<cv::GComputation, cv::gapi::wip::GStreamerSource::OutputType>>
{ };
TEST_P(GStreamerMultiSourceTest, ImageDataTest)
TEST_P(GStreamerMultiSourceTestNV12, ImageDataTest)
{
std::string pathToLeftIm = findDataFile("cv/stereomatching/datasets/tsukuba/im6.png");
std::string pathToRightIm = findDataFile("cv/stereomatching/datasets/tsukuba/im2.png");
@@ -377,7 +449,7 @@ TEST_P(GStreamerMultiSourceTest, ImageDataTest)
EXPECT_FALSE(compiled.running());
}
INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGMatsTest, GStreamerMultiSourceTest,
INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGMatsTest, GStreamerMultiSourceTestNV12,
Combine(Values(cv::GComputation([]()
{
cv::GMat in1, in2;
@@ -387,7 +459,7 @@ INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGMatsTest, GStreamerMultiSourceTe
})),
Values(cv::gapi::wip::GStreamerSource::OutputType::MAT)));
INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGFramesTest, GStreamerMultiSourceTest,
INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGFramesTest, GStreamerMultiSourceTestNV12,
Combine(Values(cv::GComputation([]()
{
cv::GFrame in1, in2;
@@ -396,6 +468,96 @@ INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGFramesTest, GStreamerMultiSource
cv::gapi::streaming::BGR(in2)));
})),
Values(cv::gapi::wip::GStreamerSource::OutputType::FRAME)));
struct GStreamerMultiSourceTestGRAY8 :
public TestWithParam<std::tuple<cv::GComputation, cv::gapi::wip::GStreamerSource::OutputType>>
{ };
TEST_P(GStreamerMultiSourceTestGRAY8, ImageDataTest)
{
std::string pathToLeftIm = findDataFile("cv/stereomatching/datasets/tsukuba/im6.png");
std::string pathToRightIm = findDataFile("cv/stereomatching/datasets/tsukuba/im2.png");
std::string pipelineToReadImage("filesrc location=LOC ! pngdec ! videoconvert ! "
"videoscale ! video/x-raw,format=GRAY8 ! appsink");
cv::gapi::wip::GStreamerSource leftImageProvider(
std::regex_replace(pipelineToReadImage, std::regex("LOC"), pathToLeftIm));
cv::gapi::wip::GStreamerSource rightImageProvider(
std::regex_replace(pipelineToReadImage, std::regex("LOC"), pathToRightIm));
cv::gapi::wip::Data leftImData, rightImData;
leftImageProvider.pull(leftImData);
rightImageProvider.pull(rightImData);
cv::Mat leftRefMat = cv::util::get<cv::Mat>(leftImData);
cv::Mat rightRefMat = cv::util::get<cv::Mat>(rightImData);
// Retrieve test parameters:
std::tuple<cv::GComputation, cv::gapi::wip::GStreamerSource::OutputType> params = GetParam();
cv::GComputation extractImage = std::move(std::get<0>(params));
cv::gapi::wip::GStreamerSource::OutputType outputType = std::get<1>(params);
// Graph compilation for streaming mode:
auto compiled =
extractImage.compileStreaming();
EXPECT_TRUE(compiled);
EXPECT_FALSE(compiled.running());
cv::gapi::wip::GStreamerPipeline
pipeline(std::string("multifilesrc location=" + pathToLeftIm + " index=0 loop=true ! "
"pngdec ! videoconvert ! videoscale ! video/x-raw,format=GRAY8 ! "
"appsink name=sink1 ") +
std::string("multifilesrc location=" + pathToRightIm + " index=0 loop=true ! "
"pngdec ! videoconvert ! videoscale ! video/x-raw,format=GRAY8 ! "
"appsink name=sink2"));
// GStreamer streaming sources configuration:
auto src1 = pipeline.getStreamingSource("sink1", outputType);
auto src2 = pipeline.getStreamingSource("sink2", outputType);
compiled.setSource(cv::gin(src1, src2));
// Start of streaming:
compiled.start();
EXPECT_TRUE(compiled.running());
// Streaming - pulling of frames:
cv::Mat in_mat1, in_mat2;
std::size_t counter { }, limit { 10 };
while(compiled.pull(cv::gout(in_mat1, in_mat2)) && (counter < limit)) {
EXPECT_EQ(0, cv::norm(in_mat1, leftRefMat, cv::NORM_INF));
EXPECT_EQ(0, cv::norm(in_mat2, rightRefMat, cv::NORM_INF));
++counter;
}
compiled.stop();
EXPECT_FALSE(compiled.running());
}
INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGMatsTest, GStreamerMultiSourceTestGRAY8,
Combine(Values(cv::GComputation([]()
{
cv::GMat in1, in2;
return cv::GComputation(cv::GIn(in1, in2),
cv::GOut(cv::gapi::copy(in1),
cv::gapi::copy(in2)));
})),
Values(cv::gapi::wip::GStreamerSource::OutputType::MAT)));
INSTANTIATE_TEST_CASE_P(GStreamerMultiSourceViaGFramesTest, GStreamerMultiSourceTestGRAY8,
Combine(Values(cv::GComputation([]()
{
cv::GFrame in1, in2;
return cv::GComputation(cv::GIn(in1, in2),
cv::GOut(cv::gapi::streaming::BGR(in1),
cv::gapi::streaming::BGR(in2)));
})),
Values(cv::gapi::wip::GStreamerSource::OutputType::FRAME)));
} // namespace opencv_test
#endif // HAVE_GSTREAMER
@@ -164,6 +164,26 @@ public:
}
};
class TestMediaGRAY final : public cv::MediaFrame::IAdapter {
cv::Mat m_mat;
using Cb = cv::MediaFrame::View::Callback;
Cb m_cb;
public:
explicit TestMediaGRAY(cv::Mat m, Cb cb = []() {})
: m_mat(m), m_cb(cb) {
}
cv::GFrameDesc meta() const override {
return cv::GFrameDesc{ cv::MediaFormat::GRAY, cv::Size(m_mat.cols, m_mat.rows) };
}
cv::MediaFrame::View access(cv::MediaFrame::Access) override {
cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{ m_cb });
}
};
class BGRSource : public cv::gapi::wip::GCaptureSource {
public:
explicit BGRSource(const std::string& pipeline)
@@ -230,6 +250,31 @@ public:
}
};
class GRAYSource : public cv::gapi::wip::GCaptureSource {
public:
explicit GRAYSource(const std::string& pipeline)
: cv::gapi::wip::GCaptureSource(pipeline) {
}
bool pull(cv::gapi::wip::Data& data) {
if (cv::gapi::wip::GCaptureSource::pull(data)) {
cv::Mat bgr = cv::util::get<cv::Mat>(data);
cv::Mat gray;
cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);
data = cv::MediaFrame::Create<TestMediaGRAY>(gray);
return true;
}
return false;
}
GMetaArg descr_of() const override {
return cv::GMetaArg{ cv::GFrameDesc{cv::MediaFormat::GRAY,
cv::util::get<cv::GMatDesc>(
cv::gapi::wip::GCaptureSource::descr_of()).size} };
}
};
void checkPullOverload(const cv::Mat& ref,
const bool has_output,
cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& args) {
@@ -1789,6 +1834,46 @@ TEST(GAPI_Streaming, CopyFrame)
}
}
TEST(GAPI_Streaming, CopyFrameGray)
{
std::string filepath = findDataFile("cv/video/768x576.avi");
cv::GFrame in;
auto out = cv::gapi::copy(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
auto cc = comp.compileStreaming();
try {
cc.setSource<GRAYSource>(filepath);
}
catch (...) {
throw SkipTestException("Video file can not be opened");
}
cv::VideoCapture cap;
cap.open(filepath);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
cv::MediaFrame frame;
cv::Mat ocv_mat;
std::size_t num_frames = 0u;
std::size_t max_frames = 10u;
cc.start();
while (cc.pull(cv::gout(frame)) && num_frames < max_frames)
{
auto view = frame.access(cv::MediaFrame::Access::R);
cv::Mat gapi_mat(frame.desc().size, CV_8UC1, view.ptr[0]);
num_frames++;
cap >> ocv_mat;
cv::Mat gray;
cvtColor(ocv_mat, gray, cv::COLOR_BGR2GRAY);
EXPECT_EQ(0, cvtest::norm(gray, gapi_mat, NORM_INF));
}
}
TEST(GAPI_Streaming, CopyMat)
{
std::string filepath = findDataFile("cv/video/768x576.avi");
@@ -1892,23 +1977,97 @@ TEST(GAPI_Streaming, Reshape)
}
}
TEST(GAPI_Streaming, ReshapeGray)
{
std::string filepath = findDataFile("cv/video/768x576.avi");
cv::GFrame in;
auto out = cv::gapi::copy(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
auto cc = comp.compileStreaming();
try {
cc.setSource<GRAYSource>(filepath);
}
catch (...) {
throw SkipTestException("Video file can not be opened");
}
cv::VideoCapture cap;
cap.open(filepath);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
cv::MediaFrame frame;
cv::Mat ocv_mat;
std::size_t num_frames = 0u;
std::size_t max_frames = 10u;
cc.start();
while (cc.pull(cv::gout(frame)) && num_frames < max_frames)
{
auto view = frame.access(cv::MediaFrame::Access::R);
cv::Mat gapi_mat(frame.desc().size, CV_8UC1, view.ptr[0]);
num_frames++;
cap >> ocv_mat;
cv::Mat gray;
cvtColor(ocv_mat, gray, cv::COLOR_BGR2GRAY);
EXPECT_EQ(0, cvtest::norm(gray, gapi_mat, NORM_INF));
}
// Reshape the graph meta
filepath = findDataFile("cv/video/1920x1080.avi");
cc.stop();
try {
cc.setSource<GRAYSource>(filepath);
}
catch (...) {
throw SkipTestException("Video file can not be opened");
}
cap.open(filepath);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
cv::MediaFrame frame2;
cv::Mat ocv_mat2;
num_frames = 0u;
cc.start();
while (cc.pull(cv::gout(frame2)) && num_frames < max_frames)
{
auto view = frame2.access(cv::MediaFrame::Access::R);
cv::Mat gapi_mat(frame2.desc().size, CV_8UC1, view.ptr[0]);
num_frames++;
cap >> ocv_mat2;
cv::Mat gray;
cvtColor(ocv_mat2, gray, cv::COLOR_BGR2GRAY);
EXPECT_EQ(0, cvtest::norm(gray, gapi_mat, NORM_INF));
}
}
namespace {
enum class TestSourceType {
BGR,
NV12
NV12,
GRAY
};
std::ostream& operator<<(std::ostream& os, TestSourceType a) {
os << "Source:";
switch (a) {
case TestSourceType::BGR: return os << "BGR";
case TestSourceType::NV12: return os << "NV12";
case TestSourceType::GRAY: return os << "GRAY";
default: CV_Assert(false && "unknown TestSourceType");
}
}
cv::gapi::wip::IStreamSource::Ptr createTestSource(TestSourceType sourceType,
const std::string& pipeline) {
assert(sourceType == TestSourceType::BGR || sourceType == TestSourceType::NV12);
assert(sourceType == TestSourceType::BGR || sourceType == TestSourceType::NV12 || sourceType == TestSourceType::GRAY);
cv::gapi::wip::IStreamSource::Ptr ptr { };
@@ -1933,6 +2092,16 @@ namespace {
}
break;
}
case TestSourceType::GRAY: {
try {
ptr = cv::gapi::wip::make_src<GRAYSource>(pipeline);
}
catch (...) {
throw SkipTestException(std::string("GRAYSource for '") + pipeline +
"' couldn't be created!");
}
break;
}
default: {
throw SkipTestException("Incorrect type of source! "
"Something went wrong in the test!");
@@ -2000,6 +2169,25 @@ namespace {
cvtBGR2NV12(bgr, y, uv);
return uv;
} },
{ std::make_pair(TestSourceType::GRAY, TestAccessType::BGR),
[](const cv::Mat& bgr) {
cv::Mat gray;
cv::cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);
cv::Mat out_bgr;
cv::cvtColor(gray, out_bgr, cv::COLOR_GRAY2BGR);
return out_bgr;
} },
{ std::make_pair(TestSourceType::GRAY, TestAccessType::Y),
[](const cv::Mat& bgr) {
cv::Mat gray;
cv::cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);
return gray;
} },
{ std::make_pair(TestSourceType::GRAY, TestAccessType::UV),
[](const cv::Mat& bgr) {
cv::Mat uv(bgr.size() / 2, CV_8UC2, cv::Scalar::all(127));
return uv;
} },
};
} // anonymous namespace
@@ -2007,6 +2195,7 @@ struct GAPI_Accessors_In_Streaming : public TestWithParam<
std::tuple<std::string,TestSourceType,TestAccessType>>
{ };
TEST_P(GAPI_Accessors_In_Streaming, AccuracyTest)
{
std::string filepath{};
@@ -2050,10 +2239,11 @@ TEST_P(GAPI_Accessors_In_Streaming, AccuracyTest)
INSTANTIATE_TEST_CASE_P(TestAccessor, GAPI_Accessors_In_Streaming,
Combine(Values("cv/video/768x576.avi"),
Values(TestSourceType::BGR, TestSourceType::NV12),
Values(TestSourceType::BGR, TestSourceType::NV12, TestSourceType::GRAY),
Values(TestAccessType::BGR, TestAccessType::Y, TestAccessType::UV)
));
struct GAPI_Accessors_Meta_In_Streaming : public TestWithParam<
std::tuple<std::string,TestSourceType,TestAccessType>>
{ };
@@ -2120,7 +2310,7 @@ TEST_P(GAPI_Accessors_Meta_In_Streaming, AccuracyTest)
INSTANTIATE_TEST_CASE_P(AccessorMeta, GAPI_Accessors_Meta_In_Streaming,
Combine(Values("cv/video/768x576.avi"),
Values(TestSourceType::BGR, TestSourceType::NV12),
Values(TestSourceType::BGR, TestSourceType::NV12, TestSourceType::GRAY),
Values(TestAccessType::BGR, TestAccessType::Y, TestAccessType::UV)
));
@@ -2232,7 +2422,7 @@ TEST(GAPI_Streaming, TestDesyncRMat) {
cv::optional<cv::RMat> out_desync;
cv::optional<cv::RMat> out_rmat;
while (true) {
// Initially it throwed "bad variant access" since there was
// Initially it threw "bad variant access" since there was
// no RMat handling in wrap_opt_arg
EXPECT_NO_THROW(pipe.pull(cv::gout(out_desync, out_rmat)));
if (out_rmat) break;
@@ -2273,11 +2463,54 @@ TEST(GAPI_Streaming, TestDesyncMediaFrame) {
cv::optional<cv::MediaFrame> out_desync;
cv::optional<cv::MediaFrame> out_frame;
while (true) {
// Initially it throwed "bad variant access" since there was
// Initially it threw "bad variant access" since there was
// no MediaFrame handling in wrap_opt_arg
EXPECT_NO_THROW(pipe.pull(cv::gout(out_desync, out_frame)));
if (out_frame) break;
}
}
G_API_OP(GTestBlurGray, <GFrame(GFrame)>, "test.blur_gray") {
static GFrameDesc outMeta(GFrameDesc d) { return d; }
};
GAPI_OCV_KERNEL(GOcvTestBlurGray, GTestBlurGray) {
static void run(const cv::MediaFrame & in, cv::MediaFrame & out) {
auto d = in.desc();
GAPI_Assert(d.fmt == cv::MediaFormat::GRAY);
auto view = in.access(cv::MediaFrame::Access::R);
cv::Mat mat(d.size, CV_8UC1, view.ptr[0]);
cv::Mat blurred;
cv::blur(mat, blurred, cv::Size{ 3,3 });
out = cv::MediaFrame::Create<TestMediaGRAY>(blurred);
}
};
TEST(GAPI_Streaming, TestDesyncMediaFrameGray) {
cv::GFrame in;
auto blurred = GTestBlurGray::on(in);
auto desynced = cv::gapi::streaming::desync(blurred);
auto out = GTestBlurGray::on(blurred);
auto pipe = cv::GComputation(cv::GIn(in), cv::GOut(desynced, out))
.compileStreaming(cv::compile_args(cv::gapi::kernels<GOcvTestBlurGray>()));
std::string filepath = findDataFile("cv/video/768x576.avi");
try {
pipe.setSource<GRAYSource>(filepath);
}
catch (...) {
throw SkipTestException("Video file can not be opened");
}
pipe.start();
cv::optional<cv::MediaFrame> out_desync;
cv::optional<cv::MediaFrame> out_frame;
while (true) {
// Initially it threw "bad variant access" since there was
// no MediaFrame handling in wrap_opt_arg
EXPECT_NO_THROW(pipe.pull(cv::gout(out_desync, out_frame)));
if (out_frame) break;
}
}
} // namespace opencv_test
@@ -29,6 +29,7 @@
#ifdef HAVE_ONEVPL
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
#include "streaming/onevpl/file_data_provider.hpp"
#include "streaming/onevpl/cfg_param_device_selector.hpp"
#include "streaming/onevpl/accelerators/surface/surface.hpp"
@@ -37,8 +38,15 @@
#include "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
#include "streaming/onevpl/accelerators/dx11_alloc_resource.hpp"
#include "streaming/onevpl/accelerators/utils/shared_lock.hpp"
#include "streaming/onevpl/engine/processing_engine_base.hpp"
#include "streaming/onevpl/engine/engine_session.hpp"
#define private public
#define protected public
#include "streaming/onevpl/engine/transcode/transcode_engine_legacy.hpp"
#include "streaming/onevpl/engine/transcode/transcode_session.hpp"
#undef protected
#undef private
#include "logger.hpp"
#define ALIGN16(value) (((value + 15) >> 4) << 4)
namespace opencv_test
{
@@ -63,9 +71,9 @@ struct TestProcessingSession : public cv::gapi::wip::onevpl::EngineSession {
EngineSession(mfx_session, {}) {
}
const mfxVideoParam& get_video_param() const override {
const mfxFrameInfo& get_video_param() const override {
static mfxVideoParam empty;
return empty;
return empty.mfx.FrameInfo;
}
};
@@ -581,7 +589,7 @@ TEST(OneVPL_Source_DX11_Accel, Init)
// Allocate surfaces for decoder
VPLAccelerationPolicy::pool_key_t key = accel.create_surface_pool(request,
mfxDecParams);
mfxDecParams.mfx.FrameInfo);
auto cand_surface = accel.get_free_surface(key).lock();
sts = MFXVideoDECODE_Init(mfx_session, &mfxDecParams);
@@ -594,6 +602,212 @@ TEST(OneVPL_Source_DX11_Accel, Init)
MFXClose(mfx_session);
MFXUnload(mfx_handle);
}
TEST(OneVPL_Source_DX11_Accel_VPL, Init)
{
using namespace cv::gapi::wip::onevpl;
std::vector<CfgParam> cfg_params_w_dx11;
cfg_params_w_dx11.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
std::unique_ptr<VPLAccelerationPolicy> acceleration_policy (new VPLDX11AccelerationPolicy(std::make_shared<CfgParamDeviceSelector>(cfg_params_w_dx11)));
mfxLoader mfx_handle = MFXLoad();
mfxConfig cfg_inst_0 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_0);
mfxVariant mfx_param_0;
mfx_param_0.Type = MFX_VARIANT_TYPE_U32;
mfx_param_0.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_0,(mfxU8 *)CfgParam::implementation_name(),
mfx_param_0), MFX_ERR_NONE);
mfxConfig cfg_inst_1 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_1);
mfxVariant mfx_param_1;
mfx_param_1.Type = MFX_VARIANT_TYPE_U32;
mfx_param_1.Data.U32 = MFX_ACCEL_MODE_VIA_D3D11;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_1,(mfxU8 *)CfgParam::acceleration_mode_name(),
mfx_param_1), MFX_ERR_NONE);
mfxConfig cfg_inst_2 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_2);
mfxVariant mfx_param_2;
mfx_param_2.Type = MFX_VARIANT_TYPE_U32;
mfx_param_2.Data.U32 = MFX_CODEC_HEVC;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_2,(mfxU8 *)CfgParam::decoder_id_name(),
mfx_param_2), MFX_ERR_NONE);
mfxConfig cfg_inst_3 = MFXCreateConfig(mfx_handle);
EXPECT_TRUE(cfg_inst_3);
mfxVariant mfx_param_3;
mfx_param_3.Type = MFX_VARIANT_TYPE_U32;
mfx_param_3.Data.U32 = MFX_EXTBUFF_VPP_SCALING;
EXPECT_EQ(MFXSetConfigFilterProperty(cfg_inst_3,
(mfxU8 *)"mfxImplDescription.mfxVPPDescription.filter.FilterFourCC",
mfx_param_3), MFX_ERR_NONE);
// create session
mfxSession mfx_session{};
mfxStatus sts = MFXCreateSession(mfx_handle, 0, &mfx_session);
EXPECT_EQ(MFX_ERR_NONE, sts);
// assign acceleration
EXPECT_NO_THROW(acceleration_policy->init(mfx_session));
// create proper bitstream
std::string file_path = findDataFile("highgui/video/big_buck_bunny.h265");
std::shared_ptr<IDataProvider> data_provider(new FileDataProvider(file_path,
{CfgParam::create_decoder_id(MFX_CODEC_HEVC)}));
IDataProvider::mfx_codec_id_type decoder_id_name = data_provider->get_mfx_codec_id();
// Prepare video param
mfxVideoParam mfxDecParams {};
mfxDecParams.mfx.CodecId = decoder_id_name;
mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
// try fetch & decode input data
sts = MFX_ERR_NONE;
std::shared_ptr<IDataProvider::mfx_bitstream> bitstream{};
do {
EXPECT_TRUE(data_provider->fetch_bitstream_data(bitstream));
sts = MFXVideoDECODE_DecodeHeader(mfx_session, bitstream.get(), &mfxDecParams);
EXPECT_TRUE(MFX_ERR_NONE == sts || MFX_ERR_MORE_DATA == sts);
} while (sts == MFX_ERR_MORE_DATA && !data_provider->empty());
EXPECT_EQ(MFX_ERR_NONE, sts);
mfxFrameAllocRequest request{};
memset(&request, 0, sizeof(request));
sts = MFXVideoDECODE_QueryIOSurf(mfx_session, &mfxDecParams, &request);
EXPECT_EQ(MFX_ERR_NONE, sts);
// Allocate surfaces for decoder
request.Type |= MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_VPPIN;
VPLAccelerationPolicy::pool_key_t decode_pool_key = acceleration_policy->create_surface_pool(request,
mfxDecParams.mfx.FrameInfo);
sts = MFXVideoDECODE_Init(mfx_session, &mfxDecParams);
EXPECT_EQ(MFX_ERR_NONE, sts);
// initialize VPLL
mfxU16 vppOutImgWidth = 672;
mfxU16 vppOutImgHeight = 382;
mfxVideoParam mfxVPPParams{0};
mfxVPPParams.vpp.In = mfxDecParams.mfx.FrameInfo;
mfxVPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12;
mfxVPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
mfxVPPParams.vpp.Out.Width = ALIGN16(vppOutImgWidth);
mfxVPPParams.vpp.Out.Height = ALIGN16(vppOutImgHeight);
mfxVPPParams.vpp.Out.CropX = 0;
mfxVPPParams.vpp.Out.CropY = 0;
mfxVPPParams.vpp.Out.CropW = vppOutImgWidth;
mfxVPPParams.vpp.Out.CropH = vppOutImgHeight;
mfxVPPParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
mfxVPPParams.vpp.Out.FrameRateExtN = 30;
mfxVPPParams.vpp.Out.FrameRateExtD = 1;
mfxVPPParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
mfxFrameAllocRequest vppRequests[2];
memset(&vppRequests, 0, sizeof(mfxFrameAllocRequest) * 2);
EXPECT_EQ(MFXVideoVPP_QueryIOSurf(mfx_session, &mfxVPPParams, vppRequests), MFX_ERR_NONE);
vppRequests[1].AllocId = 666;
VPLAccelerationPolicy::pool_key_t vpp_out_pool_key =
acceleration_policy->create_surface_pool(vppRequests[1], mfxVPPParams.vpp.Out);
EXPECT_EQ(MFXVideoVPP_Init(mfx_session, &mfxVPPParams), MFX_ERR_NONE);
// finalize session creation
DecoderParams d_param{bitstream, mfxDecParams};
TranscoderParams t_param{mfxVPPParams};
VPLLegacyTranscodeEngine engine(std::move(acceleration_policy));
std::shared_ptr<LegacyTranscodeSession> sess_ptr =
engine.register_session<LegacyTranscodeSession>(
mfx_session,
std::move(d_param),
std::move(t_param),
data_provider);
sess_ptr->init_surface_pool(decode_pool_key);
sess_ptr->init_transcode_surface_pool(vpp_out_pool_key);
// prepare working surfaces
sess_ptr->swap_surface(engine);
sess_ptr->swap_transcode_surface(engine);
// launch pipeline
LegacyTranscodeSession & my_sess = *sess_ptr;
{
if (!my_sess.data_provider) {
my_sess.last_status = MFX_ERR_MORE_DATA;
} else {
my_sess.last_status = MFX_ERR_NONE;
if (!my_sess.data_provider->fetch_bitstream_data(my_sess.stream)) {
my_sess.last_status = MFX_ERR_MORE_DATA;
my_sess.data_provider.reset(); //close source
}
}
// 2) enqueue ASYNC decode operation
// prepare sync object for new surface
LegacyTranscodeSession::op_handle_t sync_pair{};
// enqueue decode operation with current session surface
{
my_sess.last_status =
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
(my_sess.data_provider || (my_sess.stream && my_sess.stream->DataLength))
? my_sess.stream.get()
: nullptr, /* No more data to read, start decode draining mode*/
my_sess.procesing_surface_ptr.lock()->get_handle(),
&sync_pair.second,
&sync_pair.first);
// process wait-like statuses in-place:
// It had better to use up all VPL decoding resources in pipeline
// as soon as possible. So waiting more free-surface or device free
while (my_sess.last_status == MFX_ERR_MORE_SURFACE ||
my_sess.last_status == MFX_WRN_DEVICE_BUSY) {
try {
if (my_sess.last_status == MFX_ERR_MORE_SURFACE) {
my_sess.swap_surface(engine);
}
my_sess.last_status =
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
my_sess.stream.get(),
my_sess.procesing_surface_ptr.lock()->get_handle(),
&sync_pair.second,
&sync_pair.first);
} catch (const std::runtime_error&) {
// NB: not an error, yield CPU ticks to check
// surface availability at a next phase.
break;
}
}
}
// 4) transcode
{
auto *dec_surface = sync_pair.second;
if(my_sess.vpp_surface_ptr.lock())
{
mfxFrameSurface1* out_surf = my_sess.vpp_surface_ptr.lock()->get_handle();
my_sess.last_status = MFXVideoVPP_RunFrameVPPAsync(my_sess.session, dec_surface,
out_surf,
nullptr, &sync_pair.first);
sync_pair.second = out_surf;
my_sess.last_status = MFXVideoCORE_SyncOperation(my_sess.session, sync_pair.first, 11000);
}
try {
my_sess.swap_transcode_surface(engine);
} catch (... ) {
my_sess.vpp_surface_ptr.reset();
}
}
}
}
#endif // HAVE_DIRECTX
#endif // HAVE_D3D11