123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- // 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) 2020 Intel Corporation
- #include "gapi_ocv_stateful_kernel_test_utils.hpp"
- #include <opencv2/gapi/cpu/core.hpp>
- #include <opencv2/gapi/streaming/cap.hpp>
- #include <opencv2/core.hpp>
- #include <opencv2/core/cvstd.hpp>
- #ifdef HAVE_OPENCV_VIDEO
- #include <opencv2/video.hpp>
- #endif
- namespace opencv_test
- {
- struct BackSubStateParams
- {
- std::string method;
- };
- } // namespace opencv_test
- namespace cv
- {
- namespace detail
- {
- template<> struct CompileArgTag<opencv_test::BackSubStateParams>
- {
- static const char* tag()
- {
- return "org.opencv.test.background_substractor_state_params";
- }
- };
- } // namespace detail
- } // namespace cv
- namespace opencv_test
- {
- //TODO: test OT, Background Subtractor, Kalman with 3rd version of API
- //----------------------------------------------- Simple tests ------------------------------------------------
- namespace
- {
- G_TYPED_KERNEL(GCountCalls, <cv::GOpaque<int>(GMat)>, "org.opencv.test.count_calls")
- {
- static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
- };
- GAPI_OCV_KERNEL_ST(GOCVCountCalls, GCountCalls, int)
- {
- static void setup(const cv::GMatDesc &/* in */, std::shared_ptr<int> &state)
- {
- state.reset(new int{ });
- }
- static void run(const cv::Mat &/* in */, int &out, int& state)
- {
- out = ++state;
- }
- };
- G_TYPED_KERNEL(GIsStateUpToDate, <cv::GOpaque<bool>(GMat)>,
- "org.opencv.test.is_state_up-to-date")
- {
- static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
- };
- GAPI_OCV_KERNEL_ST(GOCVIsStateUpToDate, GIsStateUpToDate, cv::Size)
- {
- static void setup(const cv::GMatDesc &in, std::shared_ptr<cv::Size> &state)
- {
- state.reset(new cv::Size(in.size));
- }
- static void run(const cv::Mat &in , bool &out, cv::Size& state)
- {
- out = in.size() == state;
- }
- };
- G_TYPED_KERNEL(GStInvalidResize, <GMat(GMat,Size,double,double,int)>,
- "org.opencv.test.st_invalid_resize")
- {
- static GMatDesc outMeta(GMatDesc in, Size, double, double, int) { return in; }
- };
- GAPI_OCV_KERNEL_ST(GOCVStInvalidResize, GStInvalidResize, int)
- {
- static void setup(const cv::GMatDesc, cv::Size, double, double, int,
- std::shared_ptr<int> &/* state */)
- { }
- static void run(const cv::Mat& in, cv::Size sz, double fx, double fy, int interp,
- cv::Mat &out, int& /* state */)
- {
- cv::resize(in, out, sz, fx, fy, interp);
- }
- };
- G_TYPED_KERNEL(GBackSub, <GMat(GMat)>, "org.opencv.test.background_substractor")
- {
- static GMatDesc outMeta(GMatDesc in) { return in.withType(CV_8U, 1); }
- };
- #ifdef HAVE_OPENCV_VIDEO
- GAPI_OCV_KERNEL_ST(GOCVBackSub, GBackSub, cv::BackgroundSubtractor)
- {
- static void setup(const cv::GMatDesc &/* desc */,
- std::shared_ptr<BackgroundSubtractor> &state,
- const cv::GCompileArgs &compileArgs)
- {
- auto sbParams = cv::gapi::getCompileArg<BackSubStateParams>(compileArgs)
- .value_or(BackSubStateParams { });
- if (sbParams.method == "knn")
- state = createBackgroundSubtractorKNN();
- else if (sbParams.method == "mog2")
- state = createBackgroundSubtractorMOG2();
- GAPI_Assert(state);
- }
- static void run(const cv::Mat& in, cv::Mat &out, BackgroundSubtractor& state)
- {
- state.apply(in, out, -1);
- }
- };
- #endif
- };
- TEST(StatefulKernel, StateIsMutableInRuntime)
- {
- constexpr int expectedCallsCount = 10;
- cv::Mat dummyIn { 1, 1, CV_8UC1 };
- int actualCallsCount = 0;
- // Declaration of G-API expression
- GMat in;
- GOpaque<int> out = GCountCalls::on(in);
- cv::GComputation comp(cv::GIn(in), cv::GOut(out));
- const auto pkg = cv::gapi::kernels<GOCVCountCalls>();
- // Compilation of G-API expression
- auto callsCounter = comp.compile(cv::descr_of(dummyIn), cv::compile_args(pkg));
- // Simulating video stream: call GCompiled multiple times
- for (int i = 0; i < expectedCallsCount; i++)
- {
- callsCounter(cv::gin(dummyIn), cv::gout(actualCallsCount));
- EXPECT_EQ(i + 1, actualCallsCount);
- }
- // End of "video stream"
- EXPECT_EQ(expectedCallsCount, actualCallsCount);
- // User asks G-API to prepare for a new stream
- callsCounter.prepareForNewStream();
- callsCounter(cv::gin(dummyIn), cv::gout(actualCallsCount));
- EXPECT_EQ(1, actualCallsCount);
- }
- TEST(StatefulKernel, StateIsAutoResetForNewStream)
- {
- cv::GMat in;
- cv::GOpaque<bool> out = GIsStateUpToDate::on(in);
- cv::GComputation c(cv::GIn(in), cv::GOut(out));
- const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate>();
- // Compilation & testing
- auto ccomp = c.compileStreaming(cv::compile_args(pkg));
- auto path = findDataFile("cv/video/768x576.avi");
- try {
- ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
- } catch(...) {
- throw SkipTestException("Video file can not be opened");
- }
- ccomp.start();
- EXPECT_TRUE(ccomp.running());
- // Process the full video
- bool isStateUpToDate = false;
- while (ccomp.pull(cv::gout(isStateUpToDate))) {
- EXPECT_TRUE(isStateUpToDate);
- }
- EXPECT_FALSE(ccomp.running());
- path = findDataFile("cv/video/1920x1080.avi");
- try {
- ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
- } catch(...) {
- throw SkipTestException("Video file can not be opened");
- }
- ccomp.start();
- EXPECT_TRUE(ccomp.running());
- while (ccomp.pull(cv::gout(isStateUpToDate))) {
- EXPECT_TRUE(isStateUpToDate);
- }
- EXPECT_FALSE(ccomp.running());
- }
- TEST(StatefulKernel, InvalidReallocatingKernel)
- {
- cv::GMat in, out;
- cv::Mat in_mat(500, 500, CV_8UC1), out_mat;
- out = GStInvalidResize::on(in, cv::Size(300, 300), 0.0, 0.0, cv::INTER_LINEAR);
- const auto pkg = cv::gapi::kernels<GOCVStInvalidResize>();
- cv::GComputation comp(cv::GIn(in), cv::GOut(out));
- EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error);
- }
- #ifdef HAVE_OPENCV_VIDEO
- namespace
- {
- void compareBackSubResults(const cv::Mat &actual, const cv::Mat &expected,
- const int diffPercent)
- {
- GAPI_Assert(actual.size() == expected.size());
- int allowedNumDiffPixels = actual.size().area() * diffPercent / 100;
- cv::Mat diff;
- cv::absdiff(actual, expected, diff);
- cv::Mat hist(256, 1, CV_32FC1, cv::Scalar(0));
- const float range[] { 0, 256 };
- const float *histRange { range };
- calcHist(&diff, 1, 0, Mat(), hist, 1, &hist.rows, &histRange, true, false);
- for (int i = 2; i < hist.rows; ++i)
- {
- hist.at<float>(i) += hist.at<float>(i - 1);
- }
- int numDiffPixels = static_cast<int>(hist.at<float>(255));
- EXPECT_GT(allowedNumDiffPixels, numDiffPixels);
- }
- } // anonymous namespace
- TEST(StatefulKernel, StateIsInitViaCompArgs)
- {
- cv::Mat frame(1080, 1920, CV_8UC3),
- gapiForeground,
- ocvForeground;
- cv::randu(frame, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255));
- // G-API code
- cv::GMat in;
- cv::GMat out = GBackSub::on(in);
- cv::GComputation c(cv::GIn(in), cv::GOut(out));
- const auto pkg = cv::gapi::kernels<GOCVBackSub>();
- auto gapiBackSub = c.compile(cv::descr_of(frame),
- cv::compile_args(pkg, BackSubStateParams { "knn" }));
- gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
- // OpenCV code
- auto pOcvBackSub = createBackgroundSubtractorKNN();
- pOcvBackSub->apply(frame, ocvForeground);
- // Comparison
- // Allowing 1% difference of all pixels between G-API and OpenCV results
- compareBackSubResults(gapiForeground, ocvForeground, 1);
- // Additionally, test the case where state is resetted
- gapiBackSub.prepareForNewStream();
- gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
- pOcvBackSub->apply(frame, ocvForeground);
- compareBackSubResults(gapiForeground, ocvForeground, 1);
- }
- #endif
- #ifdef HAVE_OPENCV_VIDEO
- namespace
- {
- void testBackSubInStreaming(cv::GStreamingCompiled gapiBackSub, const int diffPercent)
- {
- cv::Mat frame,
- gapiForeground,
- ocvForeground;
- gapiBackSub.start();
- EXPECT_TRUE(gapiBackSub.running());
- // OpenCV reference substractor
- auto pOCVBackSub = createBackgroundSubtractorKNN();
- // Comparison of G-API and OpenCV substractors
- std::size_t frames = 0u;
- while (gapiBackSub.pull(cv::gout(frame, gapiForeground))) {
- pOCVBackSub->apply(frame, ocvForeground, -1);
- compareBackSubResults(gapiForeground, ocvForeground, diffPercent);
- frames++;
- }
- EXPECT_LT(0u, frames);
- EXPECT_FALSE(gapiBackSub.running());
- }
- } // anonymous namespace
- TEST(StatefulKernel, StateIsInitViaCompArgsInStreaming)
- {
- // G-API graph declaration
- cv::GMat in;
- cv::GMat out = GBackSub::on(in);
- // Preserving 'in' in output to have possibility to compare with OpenCV reference
- cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
- // G-API compilation of graph for streaming mode
- const auto pkg = cv::gapi::kernels<GOCVBackSub>();
- auto gapiBackSub = c.compileStreaming(
- cv::compile_args(pkg, BackSubStateParams { "knn" }));
- // Testing G-API Background Substractor in streaming mode
- auto path = findDataFile("cv/video/768x576.avi");
- try {
- gapiBackSub.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
- } catch(...) {
- throw SkipTestException("Video file can not be opened");
- }
- // Allowing 1% difference of all pixels between G-API and reference OpenCV results
- testBackSubInStreaming(gapiBackSub, 1);
- path = findDataFile("cv/video/1920x1080.avi");
- try {
- // Additionally, test the case when the new stream happens
- gapiBackSub.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
- } catch(...) {
- throw SkipTestException("Video file can not be opened");
- }
- // Allowing 5% difference of all pixels between G-API and reference OpenCV results
- testBackSubInStreaming(gapiBackSub, 5);
- }
- #endif
- //-------------------------------------------------------------------------------------------------------------
- //------------------------------------------- Typed tests on setup() ------------------------------------------
- namespace
- {
- template<typename Tuple>
- struct SetupStateTypedTest : public ::testing::Test
- {
- using StateT = typename std::tuple_element<0, Tuple>::type;
- using SetupT = typename std::tuple_element<1, Tuple>::type;
- G_TYPED_KERNEL(GReturnState, <cv::GOpaque<StateT>(GMat)>, "org.opencv.test.return_state")
- {
- static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
- };
- GAPI_OCV_KERNEL_ST(GOCVReturnState, GReturnState, StateT)
- {
- static void setup(const cv::GMatDesc &/* in */, std::shared_ptr<StateT> &state)
- {
- // Don't use input cv::GMatDesc intentionally
- state.reset(new StateT(SetupT::value()));
- }
- static void run(const cv::Mat &/* in */, StateT &out, StateT& state)
- {
- out = state;
- }
- };
- };
- TYPED_TEST_CASE_P(SetupStateTypedTest);
- } // namespace
- TYPED_TEST_P(SetupStateTypedTest, ReturnInitializedState)
- {
- using StateType = typename TestFixture::StateT;
- using SetupType = typename TestFixture::SetupT;
- cv::Mat dummyIn { 1, 1, CV_8UC1 };
- StateType retState { };
- GMat in;
- auto out = TestFixture::GReturnState::on(in);
- cv::GComputation comp(cv::GIn(in), cv::GOut(out));
- const auto pkg = cv::gapi::kernels<typename TestFixture::GOCVReturnState>();
- comp.apply(cv::gin(dummyIn), cv::gout(retState), cv::compile_args(pkg));
- EXPECT_EQ(SetupType::value(), retState);
- }
- REGISTER_TYPED_TEST_CASE_P(SetupStateTypedTest,
- ReturnInitializedState);
- DEFINE_INITIALIZER(CharValue, char, 'z');
- DEFINE_INITIALIZER(IntValue, int, 7);
- DEFINE_INITIALIZER(FloatValue, float, 42.f);
- DEFINE_INITIALIZER(UcharPtrValue, uchar*, nullptr);
- namespace
- {
- using Std3IntArray = std::array<int, 3>;
- }
- DEFINE_INITIALIZER(StdArrayValue, Std3IntArray, { 1, 2, 3 });
- DEFINE_INITIALIZER(UserValue, UserStruct, { 5, 7.f });
- using TypesToVerify = ::testing::Types<std::tuple<char, CharValue>,
- std::tuple<int, IntValue>,
- std::tuple<float, FloatValue>,
- std::tuple<uchar*, UcharPtrValue>,
- std::tuple<std::array<int, 3>, StdArrayValue>,
- std::tuple<UserStruct, UserValue>>;
- INSTANTIATE_TYPED_TEST_CASE_P(SetupStateTypedInst, SetupStateTypedTest, TypesToVerify);
- //-------------------------------------------------------------------------------------------------------------
- } // opencv_test
|