From e6f52b0996d8e4f96ed13e501b4166805f09024b Mon Sep 17 00:00:00 2001 From: aDanPin Date: Wed, 31 Mar 2021 20:09:10 +0300 Subject: [PATCH] Adding stereo operation and tests --- modules/gapi/CMakeLists.txt | 4 +- .../gapi/include/opencv2/gapi/cpu/stereo.hpp | 48 +++++++++++ modules/gapi/include/opencv2/gapi/stereo.hpp | 64 ++++++++++++++ modules/gapi/src/api/kernels_stereo.cpp | 18 ++++ modules/gapi/src/backends/cpu/gcpustereo.cpp | 85 +++++++++++++++++++ .../gapi/test/common/gapi_stereo_tests.cpp | 8 ++ .../gapi/test/common/gapi_stereo_tests.hpp | 26 ++++++ .../test/common/gapi_stereo_tests_inl.hpp | 74 ++++++++++++++++ .../gapi/test/cpu/gapi_stereo_tests_cpu.cpp | 36 ++++++++ 9 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 modules/gapi/include/opencv2/gapi/cpu/stereo.hpp create mode 100644 modules/gapi/include/opencv2/gapi/stereo.hpp create mode 100644 modules/gapi/src/api/kernels_stereo.cpp create mode 100644 modules/gapi/src/backends/cpu/gcpustereo.cpp create mode 100644 modules/gapi/test/common/gapi_stereo_tests.cpp create mode 100644 modules/gapi/test/common/gapi_stereo_tests.hpp create mode 100644 modules/gapi/test/common/gapi_stereo_tests_inl.hpp create mode 100644 modules/gapi/test/cpu/gapi_stereo_tests_cpu.cpp diff --git a/modules/gapi/CMakeLists.txt b/modules/gapi/CMakeLists.txt index 9dc393fb8a..6753c93b7d 100644 --- a/modules/gapi/CMakeLists.txt +++ b/modules/gapi/CMakeLists.txt @@ -23,7 +23,7 @@ ocv_add_module(gapi REQUIRED opencv_imgproc OPTIONAL - opencv_video + opencv_video opencv_calib3d WRAP python ) @@ -76,6 +76,7 @@ set(gapi_srcs src/api/kernels_video.cpp src/api/kernels_nnparsers.cpp src/api/kernels_streaming.cpp + src/api/kernels_stereo.cpp src/api/render.cpp src/api/render_ocv.cpp src/api/ginfer.cpp @@ -111,6 +112,7 @@ set(gapi_srcs src/backends/cpu/gcpubackend.cpp src/backends/cpu/gcpukernel.cpp src/backends/cpu/gcpuimgproc.cpp + src/backends/cpu/gcpustereo.cpp src/backends/cpu/gcpuvideo.cpp src/backends/cpu/gcpucore.cpp src/backends/cpu/gnnparsers.cpp diff --git a/modules/gapi/include/opencv2/gapi/cpu/stereo.hpp b/modules/gapi/include/opencv2/gapi/cpu/stereo.hpp new file mode 100644 index 0000000000..f7d79e9b3c --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/cpu/stereo.hpp @@ -0,0 +1,48 @@ +// 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 + +#ifndef OPENCV_GAPI_CPU_STEREO_API_HPP +#define OPENCV_GAPI_CPU_STEREO_API_HPP + +#include // GKernelPackage + +namespace cv { +namespace gapi { +namespace calib3d { +namespace cpu { + +GAPI_EXPORTS GKernelPackage kernels(); + +/** @brief Structure for the Stereo operation initialization parameters.*/ +struct GAPI_EXPORTS StereoInitParam { + StereoInitParam(int nD, int bS, double bL, double f): + numDisparities(nD), blockSize(bS), baseline(bL), focus(f) {} + + StereoInitParam() = default; + + int numDisparities = 0; + int blockSize = 21; + double baseline = 70.; + double focus = 1000.; +}; + +} // namespace cpu +} // namespace calib3d +} // namespace gapi + +namespace detail { + + template<> struct CompileArgTag { + static const char* tag() { + return "org.opencv.stereoInit"; + } +}; + +} // namespace detail +} // namespace cv + + +#endif // OPENCV_GAPI_CPU_STEREO_API_HPP diff --git a/modules/gapi/include/opencv2/gapi/stereo.hpp b/modules/gapi/include/opencv2/gapi/stereo.hpp new file mode 100644 index 0000000000..908045d4c7 --- /dev/null +++ b/modules/gapi/include/opencv2/gapi/stereo.hpp @@ -0,0 +1,64 @@ +// 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 distereoibution and at http://opencv.org/license.html. +// +// Copyright (C) 2021 Intel Corporation + +#ifndef OPENCV_GAPI_STEREO_HPP +#define OPENCV_GAPI_STEREO_HPP + +#include +#include +#include + +namespace cv { +namespace gapi { + +enum class StereoOutputFormat { + DEPTH_FLOAT16, + DEPTH_FLOAT32, + DISPARITY_FIXED16_11_5, + DISPARITY_FIXED16_12_4 +}; + +namespace calib3d { + +G_TYPED_KERNEL(GStereo, , "org.opencv.stereo") { + static GMatDesc outMeta(const GMatDesc &left, const GMatDesc &right, const StereoOutputFormat of) { + GAPI_Assert(left.chan == 1); + GAPI_Assert(left.depth == CV_8U); + + GAPI_Assert(right.chan == 1); + GAPI_Assert(right.depth == CV_8U); + + switch(of) { + case StereoOutputFormat::DEPTH_FLOAT16: + return left.withDepth(CV_16FC1); + case StereoOutputFormat::DEPTH_FLOAT32: + return left.withDepth(CV_32FC1); + case StereoOutputFormat::DISPARITY_FIXED16_11_5: + case StereoOutputFormat::DISPARITY_FIXED16_12_4: + return left.withDepth(CV_16SC1); + default: + GAPI_Assert(false && "Unknown output format!"); + } + } +}; + +} // namespace calib3d + +/** @brief Extract disparity/depth information depending on passed StereoOutputFormat argument. +The function extracts disparity/depth information depending on passed StereoOutputFormat argument from +given stereo-pair. + +@param left left 8-bit unsigned 1-channel image of @ref CV_8UC1 type +@param right right 8-bit unsigned 1-channel image of @ref CV_8UC1 type +@param of enum to specify output kind: depth or disparity and corresponding type +*/ +GAPI_EXPORTS GMat stereo(const GMat& left, + const GMat& right, + const StereoOutputFormat of = StereoOutputFormat::DEPTH_FLOAT32); +} // namespace gapi +} // namespace cv + +#endif // OPENCV_GAPI_STEREO_HPP diff --git a/modules/gapi/src/api/kernels_stereo.cpp b/modules/gapi/src/api/kernels_stereo.cpp new file mode 100644 index 0000000000..f336e8b910 --- /dev/null +++ b/modules/gapi/src/api/kernels_stereo.cpp @@ -0,0 +1,18 @@ +// 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 + +namespace cv { namespace gapi { + +GMat stereo(const GMat& left, const GMat& right, + const cv::gapi::StereoOutputFormat of) +{ + return calib3d::GStereo::on(left, right, of); +} + +} // namespace cv +} // namespace gapi diff --git a/modules/gapi/src/backends/cpu/gcpustereo.cpp b/modules/gapi/src/backends/cpu/gcpustereo.cpp new file mode 100644 index 0000000000..9b51d23992 --- /dev/null +++ b/modules/gapi/src/backends/cpu/gcpustereo.cpp @@ -0,0 +1,85 @@ +// 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 +#include +#include + +#ifdef HAVE_OPENCV_CALIB3D +#include +#endif // HAVE_OPENCV_CALIB3D + +#ifdef HAVE_OPENCV_CALIB3D + +/** @brief Structure for the Stereo operation setup parameters.*/ +struct GAPI_EXPORTS StereoSetup { + double baseline; + double focus; + cv::Ptr stereoBM; +}; + +namespace { +cv::Mat calcDepth(const cv::Mat &left, const cv::Mat &right, + const StereoSetup &ss) { + constexpr int DISPARITY_SHIFT_16S = 4; + cv::Mat disp; + ss.stereoBM->compute(left, right, disp); + disp.convertTo(disp, CV_32FC1, 1./(1 << DISPARITY_SHIFT_16S), 0); + return (ss.focus * ss.baseline) / disp; +} +} // anonymous namespace + +GAPI_OCV_KERNEL_ST(GCPUStereo, cv::gapi::calib3d::GStereo, StereoSetup) +{ + static void setup(const cv::GMatDesc&, const cv::GMatDesc&, + const cv::gapi::StereoOutputFormat, + std::shared_ptr &stereoSetup, + const cv::GCompileArgs &compileArgs) { + auto stereoInit = cv::gapi::getCompileArg(compileArgs) + .value_or(cv::gapi::calib3d::cpu::StereoInitParam{}); + + StereoSetup ss{stereoInit.baseline, + stereoInit.focus, + cv::StereoBM::create(stereoInit.numDisparities, + stereoInit.blockSize)}; + stereoSetup = std::make_shared(ss); + } + static void run(const cv::Mat& left, + const cv::Mat& right, + const cv::gapi::StereoOutputFormat oF, + cv::Mat& out_mat, + const StereoSetup &stereoSetup) { + switch(oF){ + case cv::gapi::StereoOutputFormat::DEPTH_FLOAT16: + calcDepth(left, right, stereoSetup).convertTo(out_mat, CV_16FC1); + break; + case cv::gapi::StereoOutputFormat::DEPTH_FLOAT32: + calcDepth(left, right, stereoSetup).copyTo(out_mat); + break; + case cv::gapi::StereoOutputFormat::DISPARITY_FIXED16_12_4: + stereoSetup.stereoBM->compute(left, right, out_mat); + break; + case cv::gapi::StereoOutputFormat::DISPARITY_FIXED16_11_5: + GAPI_Assert(false && "This case may be supported in future."); + default: + GAPI_Assert(false && "Unknown output format!"); + } + } +}; + +cv::gapi::GKernelPackage cv::gapi::calib3d::cpu::kernels() { + static auto pkg = cv::gapi::kernels(); + return pkg; +} + +#else + +cv::gapi::GKernelPackage cv::gapi::calib3d::cpu::kernels() +{ + return GKernelPackage(); +} + +#endif // HAVE_OPENCV_CALIB3D diff --git a/modules/gapi/test/common/gapi_stereo_tests.cpp b/modules/gapi/test/common/gapi_stereo_tests.cpp new file mode 100644 index 0000000000..12114229e3 --- /dev/null +++ b/modules/gapi/test/common/gapi_stereo_tests.cpp @@ -0,0 +1,8 @@ +// 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" +#include "gapi_stereo_tests_inl.hpp" diff --git a/modules/gapi/test/common/gapi_stereo_tests.hpp b/modules/gapi/test/common/gapi_stereo_tests.hpp new file mode 100644 index 0000000000..576f23024c --- /dev/null +++ b/modules/gapi/test/common/gapi_stereo_tests.hpp @@ -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 + + +#ifndef OPENCV_GAPI_STEREO_TESTS_HPP +#define OPENCV_GAPI_STEREO_TESTS_HPP + + +#include // fore cv::gapi::StereoOutputFormat + +#include "gapi_tests_common.hpp" +#include "gapi_parsers_tests_common.hpp" + +namespace opencv_test +{ + +GAPI_TEST_FIXTURE(TestGAPIStereo, initMatsRandU, FIXTURE_API(cv::gapi::StereoOutputFormat, int, int, double, double, CompareMats), 6, + oF, numDisparities, blockSize, baseline, + focus, cmpF) + +} // namespace opencv_test + +#endif // OPENCV_GAPI_STEREO_TESTS_HPP diff --git a/modules/gapi/test/common/gapi_stereo_tests_inl.hpp b/modules/gapi/test/common/gapi_stereo_tests_inl.hpp new file mode 100644 index 0000000000..79505317bc --- /dev/null +++ b/modules/gapi/test/common/gapi_stereo_tests_inl.hpp @@ -0,0 +1,74 @@ +// 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 + +#ifndef OPENCV_GAPI_STEREO_TESTS_INL_HPP +#define OPENCV_GAPI_STEREO_TESTS_INL_HPP + + +#include +#include +#include "gapi_stereo_tests.hpp" + +#ifdef HAVE_OPENCV_CALIB3D + +#include + +namespace opencv_test { + +TEST_P(TestGAPIStereo, DisparityDepthTest) +{ + using format = cv::gapi::StereoOutputFormat; + switch(oF) { + case format::DEPTH_FLOAT16: dtype = CV_16FC1; break; + case format::DEPTH_FLOAT32: dtype = CV_32FC1; break; + case format::DISPARITY_FIXED16_12_4: dtype = CV_16SC1; break; + default: GAPI_Assert(false && "Unsupported format in test"); + } + initOutMats(sz, dtype); + + // G-API + cv::GMat inL, inR; + cv::GMat out = cv::gapi::stereo(inL, inR, oF); + + cv::GComputation(cv::GIn(inL, inR), cv::GOut(out)) + .apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat_gapi), + cv::compile_args(cv::gapi::calib3d::cpu::kernels(), + cv::gapi::calib3d::cpu::StereoInitParam { + numDisparities, + blockSize, + baseline, + focus})); + + // OpenCV + cv::StereoBM::create(numDisparities, blockSize)->compute(in_mat1, + in_mat2, + out_mat_ocv); + + static const int DISPARITY_SHIFT_16S = 4; + switch(oF) { + case format::DEPTH_FLOAT16: + out_mat_ocv.convertTo(out_mat_ocv, CV_32FC1, 1./(1 << DISPARITY_SHIFT_16S), 0); + out_mat_ocv = (focus * baseline) / out_mat_ocv; + out_mat_ocv.convertTo(out_mat_ocv, CV_16FC1); + break; + case format::DEPTH_FLOAT32: + out_mat_ocv.convertTo(out_mat_ocv, CV_32FC1, 1./(1 << DISPARITY_SHIFT_16S), 0); + out_mat_ocv = (focus * baseline) / out_mat_ocv; + break; + case format::DISPARITY_FIXED16_12_4: + break; + default: + GAPI_Assert(false && "Unsupported format in test"); + } + + EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv)); +} + +} // namespace opencv_test + +#endif // HAVE_OPENCV_CALIB3D + +#endif // OPENCV_GAPI_STEREO_TESTS_INL_HPP diff --git a/modules/gapi/test/cpu/gapi_stereo_tests_cpu.cpp b/modules/gapi/test/cpu/gapi_stereo_tests_cpu.cpp new file mode 100644 index 0000000000..5a70b5faea --- /dev/null +++ b/modules/gapi/test/cpu/gapi_stereo_tests_cpu.cpp @@ -0,0 +1,36 @@ +// 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" +#include "../common/gapi_stereo_tests.hpp" + +#include // For ::gapi::stereo::disparity/depth +#include + +namespace +{ +#define STEREO_CPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::calib3d::cpu::kernels()}); } +} // anonymous namespace + +namespace opencv_test +{ + +INSTANTIATE_TEST_CASE_P(CPU_Tests, TestGAPIStereo, + Combine(Values(CV_8UC1), + Values(cv::Size(1280, 720)), + Values(CV_32FC1), + Values(STEREO_CPU), + Values(cv::gapi::StereoOutputFormat::DEPTH_FLOAT16, + cv::gapi::StereoOutputFormat::DEPTH_FLOAT32, + cv::gapi::StereoOutputFormat::DISPARITY_FIXED16_12_4), + Values(16), + Values(43), + Values(10.), + Values(100.), + Values(AbsExact().to_compare_obj()))); + +} // opencv_test