diff --git a/modules/stereo/CMakeLists.txt b/modules/stereo/CMakeLists.txt index 7863cbf8d..827331b81 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 b302c1334..197d762b6 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 @@ public: * 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 @@ public: * @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 @@ public: * @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 @@ public: * @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 @@ public: * @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 @@ public: * @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 @@ public: * @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 000000000..6fba7e053 --- /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 000000000..2023123eb --- /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 0e257def2..e78223666 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 000000000..a6059e701 --- /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(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) +disp = stereo.getDisparity(80) +cv.imshow("disparity", disp) +cv.waitKey() +dense_matches = stereo.getDenseMatches() +try: + 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: + print("Cannot open file") diff --git a/modules/stereo/src/quasi_dense_stereo.cpp b/modules/stereo/src/quasi_dense_stereo.cpp index 7a6513cb8..a4d196ae1 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 @@ public: 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 @@ public: // 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 @@ public: // 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 @@ public: 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 @@ public: * @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 @@ public: //------------------------------------------------------------------------- - 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