From 168c55f06141c92c5188a72004f4fad51ba95bd2 Mon Sep 17 00:00:00 2001 From: LaurentBerger Date: Thu, 14 Jan 2021 17:40:44 +0100 Subject: [PATCH 1/2] solved issue 2813 --- modules/stereo/CMakeLists.txt | 2 +- .../opencv2/stereo/quasi_dense_stereo.hpp | 66 ++++++++++--------- .../stereo/misc/python/pyopencv_stereo.hpp | 17 +++++ .../stereo/misc/python/test/test_stereo.py | 20 ++++++ modules/stereo/samples/dense_disparity.cpp | 2 +- modules/stereo/samples/sample_quasi_dense.py | 21 ++++++ modules/stereo/src/quasi_dense_stereo.cpp | 20 +++--- 7 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 modules/stereo/misc/python/pyopencv_stereo.hpp create mode 100644 modules/stereo/misc/python/test/test_stereo.py create mode 100644 modules/stereo/samples/sample_quasi_dense.py diff --git a/modules/stereo/CMakeLists.txt b/modules/stereo/CMakeLists.txt index 7863cbf8d30..827331b81e9 100644 --- a/modules/stereo/CMakeLists.txt +++ b/modules/stereo/CMakeLists.txt @@ -1,2 +1,2 @@ set(the_description "Stereo Correspondence") -ocv_define_module(stereo opencv_imgproc opencv_features2d opencv_core opencv_tracking) +ocv_define_module(stereo opencv_imgproc opencv_features2d opencv_core opencv_tracking WRAP python) diff --git a/modules/stereo/include/opencv2/stereo/quasi_dense_stereo.hpp b/modules/stereo/include/opencv2/stereo/quasi_dense_stereo.hpp index b302c133464..197d762b6c7 100644 --- a/modules/stereo/include/opencv2/stereo/quasi_dense_stereo.hpp +++ b/modules/stereo/include/opencv2/stereo/quasi_dense_stereo.hpp @@ -24,42 +24,44 @@ namespace stereo // A basic match structure -struct CV_EXPORTS Match +struct CV_EXPORTS_W_SIMPLE MatchQuasiDense { - cv::Point2i p0; - cv::Point2i p1; - float corr; + CV_PROP_RW cv::Point2i p0; + CV_PROP_RW cv::Point2i p1; + CV_PROP_RW float corr; - bool operator < (const Match & rhs) const//fixme may be used uninitialized in this function + CV_WRAP MatchQuasiDense() { corr = 0; } + + CV_WRAP_AS(apply) bool operator < (const MatchQuasiDense & rhs) const//fixme may be used uninitialized in this function { return this->corr < rhs.corr; } }; -struct CV_EXPORTS PropagationParameters +struct CV_EXPORTS_W_SIMPLE PropagationParameters { - int corrWinSizeX; // similarity window - int corrWinSizeY; + CV_PROP_RW int corrWinSizeX; // similarity window + CV_PROP_RW int corrWinSizeY; - int borderX; // border to ignore - int borderY; + CV_PROP_RW int borderX; // border to ignore + CV_PROP_RW int borderY; //matching - float correlationThreshold; // correlation threshold - float textrureThreshold; // texture threshold + CV_PROP_RW float correlationThreshold; // correlation threshold + CV_PROP_RW float textrureThreshold; // texture threshold - int neighborhoodSize; // neighborhood size - int disparityGradient; // disparity gradient threshold + CV_PROP_RW int neighborhoodSize; // neighborhood size + CV_PROP_RW int disparityGradient; // disparity gradient threshold // Parameters for LK flow algorithm - int lkTemplateSize; - int lkPyrLvl; - int lkTermParam1; - float lkTermParam2; + CV_PROP_RW int lkTemplateSize; + CV_PROP_RW int lkPyrLvl; + CV_PROP_RW int lkTermParam1; + CV_PROP_RW float lkTermParam2; // Parameters for GFT algorithm. - float gftQualityThres; - int gftMinSeperationDist; - int gftMaxNumFeatures; + CV_PROP_RW float gftQualityThres; + CV_PROP_RW int gftMinSeperationDist; + CV_PROP_RW int gftMaxNumFeatures; }; @@ -90,14 +92,14 @@ struct CV_EXPORTS PropagationParameters * */ -class CV_EXPORTS QuasiDenseStereo +class CV_EXPORTS_W QuasiDenseStereo { public: /** * @brief destructor * Method to free all the memory allocated by matrices and vectors in this class. */ - virtual ~QuasiDenseStereo() = 0; + CV_WRAP virtual ~QuasiDenseStereo() = 0; /** @@ -113,7 +115,7 @@ class CV_EXPORTS QuasiDenseStereo * in case of video processing. * @sa loadParameters */ - virtual int loadParameters(cv::String filepath) = 0; + CV_WRAP virtual int loadParameters(cv::String filepath) = 0; /** @@ -124,7 +126,7 @@ class CV_EXPORTS QuasiDenseStereo * @note This method can be used to generate a template file for tuning the class. * @sa loadParameters */ - virtual int saveParameters(cv::String filepath) = 0; + CV_WRAP virtual int saveParameters(cv::String filepath) = 0; /** @@ -133,7 +135,7 @@ class CV_EXPORTS QuasiDenseStereo * @note The method clears the sMatches vector. * @note The returned Match elements inside the sMatches vector, do not use corr member. */ - virtual void getSparseMatches(std::vector &sMatches) = 0; + CV_WRAP virtual void getSparseMatches(CV_OUT std::vector &sMatches) = 0; /** @@ -142,7 +144,7 @@ class CV_EXPORTS QuasiDenseStereo * @note The method clears the denseMatches vector. * @note The returned Match elements inside the sMatches vector, do not use corr member. */ - virtual void getDenseMatches(std::vector &denseMatches) = 0; + CV_WRAP virtual void getDenseMatches(CV_OUT std::vector &denseMatches) = 0; @@ -158,7 +160,7 @@ class CV_EXPORTS QuasiDenseStereo * @sa sparseMatching * @sa quasiDenseMatching */ - virtual void process(const cv::Mat &imgLeft ,const cv::Mat &imgRight) = 0; + CV_WRAP virtual void process(const cv::Mat &imgLeft ,const cv::Mat &imgRight) = 0; /** @@ -169,7 +171,7 @@ class CV_EXPORTS QuasiDenseStereo * @retval cv::Point(0, 0) (NO_MATCH) if no match is found in the right image for the specified pixel location in the left image. * @note This method should be always called after process, otherwise the matches will not be correct. */ - virtual cv::Point2f getMatch(const int x, const int y) = 0; + CV_WRAP virtual cv::Point2f getMatch(const int x, const int y) = 0; /** @@ -180,13 +182,13 @@ class CV_EXPORTS QuasiDenseStereo * @sa computeDisparity * @sa quantizeDisparity */ - virtual cv::Mat getDisparity(uint8_t disparityLvls=50) = 0; + CV_WRAP virtual cv::Mat getDisparity(uint8_t disparityLvls=50) = 0; - static cv::Ptr create(cv::Size monoImgSize, cv::String paramFilepath = cv::String()); + CV_WRAP static cv::Ptr create(cv::Size monoImgSize, cv::String paramFilepath = cv::String()); - PropagationParameters Param; + CV_PROP_RW PropagationParameters Param; }; } //namespace cv diff --git a/modules/stereo/misc/python/pyopencv_stereo.hpp b/modules/stereo/misc/python/pyopencv_stereo.hpp new file mode 100644 index 00000000000..6fba7e05341 --- /dev/null +++ b/modules/stereo/misc/python/pyopencv_stereo.hpp @@ -0,0 +1,17 @@ +#ifdef HAVE_OPENCV_STEREO +typedef std::vector vector_MatchQuasiDense; + +template<> struct pyopencvVecConverter +{ + static bool to(PyObject* obj, std::vector& value, const ArgInfo& info) + { + return pyopencv_to_generic_vec(obj, value, info); + } + + static PyObject* from(const std::vector& value) + { + return pyopencv_from_generic_vec(value); + } +}; + +#endif diff --git a/modules/stereo/misc/python/test/test_stereo.py b/modules/stereo/misc/python/test/test_stereo.py new file mode 100644 index 00000000000..2023123eb93 --- /dev/null +++ b/modules/stereo/misc/python/test/test_stereo.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +import cv2 as cv + +from tests_common import NewOpenCVTests + +class quasi_dense_stereo_test(NewOpenCVTests): + + def test_simple(self): + + stereo = cv.stereo.QuasiDenseStereo_create((100, 100)) + self.assertIsNotNone(stereo) + + dense_matches = cv.stereo_MatchQuasiDense() + self.assertIsNotNone(dense_matches) + + parameters = cv.stereo_PropagationParameters() + self.assertIsNotNone(parameters) + +if __name__ == '__main__': + NewOpenCVTests.bootstrap() diff --git a/modules/stereo/samples/dense_disparity.cpp b/modules/stereo/samples/dense_disparity.cpp index 0e257def230..e7822366623 100644 --- a/modules/stereo/samples/dense_disparity.cpp +++ b/modules/stereo/samples/dense_disparity.cpp @@ -46,7 +46,7 @@ int main() //! [export] - vector matches; + vector matches; stereo->getDenseMatches(matches); std::ofstream dense("./dense.txt", std::ios::out); for (uint i=0; i< matches.size(); i++) diff --git a/modules/stereo/samples/sample_quasi_dense.py b/modules/stereo/samples/sample_quasi_dense.py new file mode 100644 index 00000000000..43d57939332 --- /dev/null +++ b/modules/stereo/samples/sample_quasi_dense.py @@ -0,0 +1,21 @@ +import numpy as np +import cv2 as cv + +left_img = cv.imread("G:/Lib/opencv/samples/data/aloeL.jpg", cv.IMREAD_COLOR) +right_img = cv.imread("G:/Lib/opencv/samples/data/aloeR.jpg", cv.IMREAD_COLOR) + +frame_size = leftImg.shape[0:2]; + +stereo = cv.stereo.QuasiDenseStereo_create(frame_size[::-1]) +stereo.process(left_img,right_img) +disp = stereo.getDisparity(80) +cv.imshow("disparity", disp) +cv.waitKey() +dense_matches = stereo.getDenseMatches() +try: + f = open("dense.txt", "wt") + with f: + for idx in range(0, min(10, len(dense_matches))): + nb = f.write(str(dense_matches[idx].p0) + "\t" + str(dense_matches[idx].p1) + "\t" + str(dense_matches[idx].corr) + "\n") +except: + print("Cannot open file") diff --git a/modules/stereo/src/quasi_dense_stereo.cpp b/modules/stereo/src/quasi_dense_stereo.cpp index 7a6513cb843..a4d196ae11b 100644 --- a/modules/stereo/src/quasi_dense_stereo.cpp +++ b/modules/stereo/src/quasi_dense_stereo.cpp @@ -13,7 +13,7 @@ namespace stereo { #define NO_MATCH cv::Point(0,0) -typedef std::priority_queue, std::less > t_matchPriorityQueue; +typedef std::priority_queue, std::less > t_matchPriorityQueue; class QuasiDenseStereoImpl : public QuasiDenseStereo @@ -165,7 +165,7 @@ class QuasiDenseStereoImpl : public QuasiDenseStereo t_matchPriorityQueue Local; // Get the best seed at the moment - Match m = seeds.top(); + MatchQuasiDense m = seeds.top(); seeds.pop(); // Ignore the border @@ -209,7 +209,7 @@ class QuasiDenseStereoImpl : public QuasiDenseStereo // push back if this is valid match if( corr > Param.correlationThreshold ) { - Match nm; + MatchQuasiDense nm; nm.p0 = p0; nm.p1 = p1; nm.corr = corr; @@ -223,7 +223,7 @@ class QuasiDenseStereoImpl : public QuasiDenseStereo // Get seeds from the local while( !Local.empty() ) { - Match lm = Local.top(); + MatchQuasiDense lm = Local.top(); Local.pop(); // Check if its unique in both ref and dst. if(refMap.at(lm.p0.y, lm.p0.x) != NO_MATCH) @@ -410,7 +410,7 @@ class QuasiDenseStereoImpl : public QuasiDenseStereo for(uint i=0; i < featuresLeft.size(); i++) { // Calculate correlation and store match in Seeds. - Match m; + MatchQuasiDense m; m.p0 = cv::Point2i(featuresLeft[i]); m.p1 = cv::Point2i(featuresRight[i]); m.corr = 0; @@ -442,7 +442,7 @@ class QuasiDenseStereoImpl : public QuasiDenseStereo * @retval true If the feature is in the border of the image. * @retval false If the feature is not in the border of image. */ - bool CheckBorder(Match m, int bx, int by, int w, int h) + bool CheckBorder(MatchQuasiDense m, int bx, int by, int w, int h) { if(m.p0.xw-bx || m.p0.yh-by || m.p1.xw-bx || m.p1.yh-by) @@ -492,9 +492,9 @@ class QuasiDenseStereoImpl : public QuasiDenseStereo //------------------------------------------------------------------------- - void getSparseMatches(std::vector &sMatches) override + void getSparseMatches(std::vector &sMatches) override { - Match tmpMatch; + MatchQuasiDense tmpMatch; sMatches.clear(); sMatches.reserve(leftFeatures.size()); for (uint i=0; i &denseMatches) override + void getDenseMatches(std::vector &denseMatches) override { - Match tmpMatch; + MatchQuasiDense tmpMatch; denseMatches.clear(); denseMatches.reserve(dMatchesLen); for (int row=0; row Date: Thu, 21 Jan 2021 10:10:48 +0100 Subject: [PATCH 2/2] review --- modules/stereo/samples/sample_quasi_dense.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/stereo/samples/sample_quasi_dense.py b/modules/stereo/samples/sample_quasi_dense.py index 43d57939332..a6059e70179 100644 --- a/modules/stereo/samples/sample_quasi_dense.py +++ b/modules/stereo/samples/sample_quasi_dense.py @@ -1,20 +1,20 @@ import numpy as np import cv2 as cv -left_img = cv.imread("G:/Lib/opencv/samples/data/aloeL.jpg", cv.IMREAD_COLOR) -right_img = cv.imread("G:/Lib/opencv/samples/data/aloeR.jpg", cv.IMREAD_COLOR) +left_img = cv.imread(cv.samples.findFile("aloeL.jpg"), cv.IMREAD_COLOR) +right_img = cv.imread(cv.samples.findFile("aloeR.jpg"), cv.IMREAD_COLOR) frame_size = leftImg.shape[0:2]; stereo = cv.stereo.QuasiDenseStereo_create(frame_size[::-1]) -stereo.process(left_img,right_img) +stereo.process(left_img, right_img) disp = stereo.getDisparity(80) cv.imshow("disparity", disp) cv.waitKey() dense_matches = stereo.getDenseMatches() try: - f = open("dense.txt", "wt") - with f: + with open("dense.txt", "wt") as f: + # if you want all matches use for idx in len(dense_matches): It can be a big file for idx in range(0, min(10, len(dense_matches))): nb = f.write(str(dense_matches[idx].p0) + "\t" + str(dense_matches[idx].p1) + "\t" + str(dense_matches[idx].corr) + "\n") except: