diff --git a/modules/gpustereo/include/opencv2/gpustereo.hpp b/modules/gpustereo/include/opencv2/gpustereo.hpp index ecda512068..06843e71bc 100644 --- a/modules/gpustereo/include/opencv2/gpustereo.hpp +++ b/modules/gpustereo/include/opencv2/gpustereo.hpp @@ -48,43 +48,24 @@ #endif #include "opencv2/core/gpu.hpp" +#include "opencv2/calib3d.hpp" namespace cv { namespace gpu { -class CV_EXPORTS StereoBM_GPU +///////////////////////////////////////// +// StereoBM + +class CV_EXPORTS StereoBM : public cv::StereoBM { public: - enum { BASIC_PRESET = 0, PREFILTER_XSOBEL = 1 }; - - enum { DEFAULT_NDISP = 64, DEFAULT_WINSZ = 19 }; - - //! the default constructor - StereoBM_GPU(); - //! the full constructor taking the camera-specific preset, number of disparities and the SAD window size. ndisparities must be multiple of 8. - StereoBM_GPU(int preset, int ndisparities = DEFAULT_NDISP, int winSize = DEFAULT_WINSZ); - - //! the stereo correspondence operator. Finds the disparity for the specified rectified stereo pair - //! Output disparity has CV_8U type. - void operator()(const GpuMat& left, const GpuMat& right, GpuMat& disparity, Stream& stream = Stream::Null()); + using cv::StereoBM::compute; - //! Some heuristics that tries to estmate - // if current GPU will be faster than CPU in this algorithm. - // It queries current active device. - static bool checkIfGpuCallReasonable(); + virtual void compute(InputArray left, InputArray right, OutputArray disparity, Stream& stream) = 0; +}; - int preset; - int ndisp; - int winSize; +CV_EXPORTS Ptr createStereoBM(int numDisparities = 64, int blockSize = 19); - // If avergeTexThreshold == 0 => post procesing is disabled - // If avergeTexThreshold != 0 then disparity is set 0 in each point (x,y) where for left image - // SumOfHorizontalGradiensInWindow(x, y, winSize) < (winSize * winSize) * avergeTexThreshold - // i.e. input left image is low textured. - float avergeTexThreshold; -private: - GpuMat minSSD, leBuf, riBuf; -}; // "Efficient Belief Propagation for Early Vision" // P.Felzenszwalb diff --git a/modules/gpustereo/perf/perf_stereo.cpp b/modules/gpustereo/perf/perf_stereo.cpp index e0438c0ae6..fde0bbaa18 100644 --- a/modules/gpustereo/perf/perf_stereo.cpp +++ b/modules/gpustereo/perf/perf_stereo.cpp @@ -63,18 +63,17 @@ PERF_TEST_P(ImagePair, StereoBM, const cv::Mat imgRight = readImage(GET_PARAM(1), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(imgRight.empty()); - const int preset = 0; const int ndisp = 256; if (PERF_RUN_GPU()) { - cv::gpu::StereoBM_GPU d_bm(preset, ndisp); + cv::Ptr d_bm = cv::gpu::createStereoBM(ndisp); const cv::gpu::GpuMat d_imgLeft(imgLeft); const cv::gpu::GpuMat d_imgRight(imgRight); cv::gpu::GpuMat dst; - TEST_CYCLE() d_bm(d_imgLeft, d_imgRight, dst); + TEST_CYCLE() d_bm->compute(d_imgLeft, d_imgRight, dst); GPU_SANITY_CHECK(dst); } diff --git a/modules/gpustereo/src/stereobm.cpp b/modules/gpustereo/src/stereobm.cpp index f8e6c20fb5..9b32cf7e92 100644 --- a/modules/gpustereo/src/stereobm.cpp +++ b/modules/gpustereo/src/stereobm.cpp @@ -47,11 +47,7 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -cv::gpu::StereoBM_GPU::StereoBM_GPU() { throw_no_cuda(); } -cv::gpu::StereoBM_GPU::StereoBM_GPU(int, int, int) { throw_no_cuda(); } - -bool cv::gpu::StereoBM_GPU::checkIfGpuCallReasonable() { throw_no_cuda(); return false; } -void cv::gpu::StereoBM_GPU::operator() ( const GpuMat&, const GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } +Ptr cv::gpu::createStereoBM(int, int) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -67,74 +63,123 @@ namespace cv { namespace gpu { namespace cudev namespace { - const float defaultAvgTexThreshold = 3; -} + class StereoBMImpl : public gpu::StereoBM + { + public: + StereoBMImpl(int numDisparities, int blockSize); -cv::gpu::StereoBM_GPU::StereoBM_GPU() - : preset(BASIC_PRESET), ndisp(DEFAULT_NDISP), winSize(DEFAULT_WINSZ), avergeTexThreshold(defaultAvgTexThreshold) -{ -} + void compute(InputArray left, InputArray right, OutputArray disparity); + void compute(InputArray left, InputArray right, OutputArray disparity, Stream& stream); -cv::gpu::StereoBM_GPU::StereoBM_GPU(int preset_, int ndisparities_, int winSize_) - : preset(preset_), ndisp(ndisparities_), winSize(winSize_), avergeTexThreshold(defaultAvgTexThreshold) -{ - const int max_supported_ndisp = 1 << (sizeof(unsigned char) * 8); - CV_Assert(0 < ndisp && ndisp <= max_supported_ndisp); - CV_Assert(ndisp % 8 == 0); - CV_Assert(winSize % 2 == 1); -} + int getMinDisparity() const { return 0; } + void setMinDisparity(int /*minDisparity*/) {} -bool cv::gpu::StereoBM_GPU::checkIfGpuCallReasonable() -{ - if (0 == getCudaEnabledDeviceCount()) - return false; + int getNumDisparities() const { return ndisp_; } + void setNumDisparities(int numDisparities) { ndisp_ = numDisparities; } - DeviceInfo device_info; + int getBlockSize() const { return winSize_; } + void setBlockSize(int blockSize) { winSize_ = blockSize; } - if (device_info.major() > 1 || device_info.multiProcessorCount() > 16) - return true; + int getSpeckleWindowSize() const { return 0; } + void setSpeckleWindowSize(int /*speckleWindowSize*/) {} - return false; -} + int getSpeckleRange() const { return 0; } + void setSpeckleRange(int /*speckleRange*/) {} -namespace -{ - void stereo_bm_gpu_operator( GpuMat& minSSD, GpuMat& leBuf, GpuMat& riBuf, int preset, int ndisp, int winSize, float avergeTexThreshold, const GpuMat& left, const GpuMat& right, GpuMat& disparity, cudaStream_t stream) + int getDisp12MaxDiff() const { return 0; } + void setDisp12MaxDiff(int /*disp12MaxDiff*/) {} + + int getPreFilterType() const { return preset_; } + void setPreFilterType(int preFilterType) { preset_ = preFilterType; } + + int getPreFilterSize() const { return 0; } + void setPreFilterSize(int /*preFilterSize*/) {} + + int getPreFilterCap() const { return preFilterCap_; } + void setPreFilterCap(int preFilterCap) { preFilterCap_ = preFilterCap; } + + int getTextureThreshold() const { return avergeTexThreshold_; } + void setTextureThreshold(int textureThreshold) { avergeTexThreshold_ = textureThreshold; } + + int getUniquenessRatio() const { return 0; } + void setUniquenessRatio(int /*uniquenessRatio*/) {} + + int getSmallerBlockSize() const { return 0; } + void setSmallerBlockSize(int /*blockSize*/){} + + Rect getROI1() const { return Rect(); } + void setROI1(Rect /*roi1*/) {} + + Rect getROI2() const { return Rect(); } + void setROI2(Rect /*roi2*/) {} + + private: + int preset_; + int ndisp_; + int winSize_; + int preFilterCap_; + float avergeTexThreshold_; + + GpuMat minSSD_, leBuf_, riBuf_; + }; + + StereoBMImpl::StereoBMImpl(int numDisparities, int blockSize) + : preset_(0), ndisp_(numDisparities), winSize_(blockSize), preFilterCap_(31), avergeTexThreshold_(3) + { + } + + void StereoBMImpl::compute(InputArray left, InputArray right, OutputArray disparity) + { + compute(left, right, disparity, Stream::Null()); + } + + void StereoBMImpl::compute(InputArray _left, InputArray _right, OutputArray _disparity, Stream& _stream) { using namespace ::cv::gpu::cudev::stereobm; - CV_Assert(left.rows == right.rows && left.cols == right.cols); - CV_Assert(left.type() == CV_8UC1); - CV_Assert(right.type() == CV_8UC1); + const int max_supported_ndisp = 1 << (sizeof(unsigned char) * 8); + CV_Assert( 0 < ndisp_ && ndisp_ <= max_supported_ndisp ); + CV_Assert( ndisp_ % 8 == 0 ); + CV_Assert( winSize_ % 2 == 1 ); + + GpuMat left = _left.getGpuMat(); + GpuMat right = _right.getGpuMat(); + + CV_Assert( left.type() == CV_8UC1 ); + CV_Assert( left.size() == right.size() && left.type() == right.type() ); + + _disparity.create(left.size(), CV_8UC1); + GpuMat disparity = _disparity.getGpuMat(); + + cudaStream_t stream = StreamAccessor::getStream(_stream); - disparity.create(left.size(), CV_8U); - minSSD.create(left.size(), CV_32S); + gpu::ensureSizeIsEnough(left.size(), CV_32SC1, minSSD_); - GpuMat le_for_bm = left; - GpuMat ri_for_bm = right; + PtrStepSzb le_for_bm = left; + PtrStepSzb ri_for_bm = right; - if (preset == StereoBM_GPU::PREFILTER_XSOBEL) + if (preset_ == cv::StereoBM::PREFILTER_XSOBEL) { - leBuf.create( left.size(), left.type()); - riBuf.create(right.size(), right.type()); + gpu::ensureSizeIsEnough(left.size(), left.type(), leBuf_); + gpu::ensureSizeIsEnough(right.size(), right.type(), riBuf_); - prefilter_xsobel( left, leBuf, 31, stream); - prefilter_xsobel(right, riBuf, 31, stream); + prefilter_xsobel( left, leBuf_, preFilterCap_, stream); + prefilter_xsobel(right, riBuf_, preFilterCap_, stream); - le_for_bm = leBuf; - ri_for_bm = riBuf; + le_for_bm = leBuf_; + ri_for_bm = riBuf_; } - stereoBM_GPU(le_for_bm, ri_for_bm, disparity, ndisp, winSize, minSSD, stream); + stereoBM_GPU(le_for_bm, ri_for_bm, disparity, ndisp_, winSize_, minSSD_, stream); - if (avergeTexThreshold) - postfilter_textureness(le_for_bm, winSize, avergeTexThreshold, disparity, stream); + if (avergeTexThreshold_ > 0) + postfilter_textureness(le_for_bm, winSize_, avergeTexThreshold_, disparity, stream); } } -void cv::gpu::StereoBM_GPU::operator() ( const GpuMat& left, const GpuMat& right, GpuMat& disparity, Stream& stream) +Ptr cv::gpu::createStereoBM(int numDisparities, int blockSize) { - stereo_bm_gpu_operator(minSSD, leBuf, riBuf, preset, ndisp, winSize, avergeTexThreshold, left, right, disparity, StreamAccessor::getStream(stream)); + return new StereoBMImpl(numDisparities, blockSize); } #endif /* !defined (HAVE_CUDA) */ diff --git a/modules/gpustereo/test/test_stereo.cpp b/modules/gpustereo/test/test_stereo.cpp index 0ead03dc5c..2046890d68 100644 --- a/modules/gpustereo/test/test_stereo.cpp +++ b/modules/gpustereo/test/test_stereo.cpp @@ -71,10 +71,10 @@ GPU_TEST_P(StereoBM, Regression) ASSERT_FALSE(right_image.empty()); ASSERT_FALSE(disp_gold.empty()); - cv::gpu::StereoBM_GPU bm(0, 128, 19); + cv::Ptr bm = cv::gpu::createStereoBM(128, 19); cv::gpu::GpuMat disp; - bm(loadMat(left_image), loadMat(right_image), disp); + bm->compute(loadMat(left_image), loadMat(right_image), disp); EXPECT_MAT_NEAR(disp_gold, disp, 0.0); } diff --git a/samples/gpu/driver_api_stereo_multi.cpp b/samples/gpu/driver_api_stereo_multi.cpp index fac9e36941..c49fc85641 100644 --- a/samples/gpu/driver_api_stereo_multi.cpp +++ b/samples/gpu/driver_api_stereo_multi.cpp @@ -85,7 +85,7 @@ void inline contextOff() // GPUs data GpuMat d_left[2]; GpuMat d_right[2]; -StereoBM_GPU* bm[2]; +Ptr bm[2]; GpuMat d_result[2]; static void printHelp() @@ -162,14 +162,14 @@ int main(int argc, char** argv) contextOn(0); d_left[0].upload(left.rowRange(0, left.rows / 2)); d_right[0].upload(right.rowRange(0, right.rows / 2)); - bm[0] = new StereoBM_GPU(); + bm[0] = gpu::createStereoBM(); contextOff(); // Split source images for processing on the GPU #1 contextOn(1); d_left[1].upload(left.rowRange(left.rows / 2, left.rows)); d_right[1].upload(right.rowRange(right.rows / 2, right.rows)); - bm[1] = new StereoBM_GPU(); + bm[1] = gpu::createStereoBM(); contextOff(); // Execute calculation in two threads using two GPUs @@ -182,7 +182,7 @@ int main(int argc, char** argv) d_left[0].release(); d_right[0].release(); d_result[0].release(); - delete bm[0]; + bm[0].release(); contextOff(); // Release the second GPU resources @@ -191,7 +191,7 @@ int main(int argc, char** argv) d_left[1].release(); d_right[1].release(); d_result[1].release(); - delete bm[1]; + bm[1].release(); contextOff(); waitKey(); @@ -204,8 +204,7 @@ void Worker::operator()(int device_id) const { contextOn(device_id); - bm[device_id]->operator()(d_left[device_id], d_right[device_id], - d_result[device_id]); + bm[device_id]->compute(d_left[device_id], d_right[device_id], d_result[device_id]); std::cout << "GPU #" << device_id << " (" << DeviceInfo().name() << "): finished\n"; diff --git a/samples/gpu/stereo_match.cpp b/samples/gpu/stereo_match.cpp index edf8886ffa..071ddf584c 100644 --- a/samples/gpu/stereo_match.cpp +++ b/samples/gpu/stereo_match.cpp @@ -65,7 +65,7 @@ private: Mat left, right; gpu::GpuMat d_left, d_right; - gpu::StereoBM_GPU bm; + Ptr bm; gpu::StereoBeliefPropagation bp; gpu::StereoConstantSpaceBP csbp; @@ -172,7 +172,7 @@ void App::run() imshow("right", right); // Set common parameters - bm.ndisp = p.ndisp; + bm = gpu::createStereoBM(p.ndisp); bp.ndisp = p.ndisp; csbp.ndisp = p.ndisp; @@ -201,7 +201,7 @@ void App::run() imshow("left", left); imshow("right", right); } - bm(d_left, d_right, d_disp); + bm->compute(d_left, d_right, d_disp); break; case Params::BP: bp(d_left, d_right, d_disp); break; case Params::CSBP: csbp(d_left, d_right, d_disp); break; @@ -228,8 +228,8 @@ void App::printParams() const switch (p.method) { case Params::BM: - cout << "win_size: " << bm.winSize << endl; - cout << "prefilter_sobel: " << bm.preset << endl; + cout << "win_size: " << bm->getBlockSize() << endl; + cout << "prefilter_sobel: " << bm->getPreFilterType() << endl; break; case Params::BP: cout << "iter_count: " << bp.iters << endl; @@ -289,44 +289,44 @@ void App::handleKey(char key) case 's': case 'S': if (p.method == Params::BM) { - switch (bm.preset) + switch (bm->getPreFilterType()) { - case gpu::StereoBM_GPU::BASIC_PRESET: - bm.preset = gpu::StereoBM_GPU::PREFILTER_XSOBEL; + case 0: + bm->setPreFilterType(cv::StereoBM::PREFILTER_XSOBEL); break; - case gpu::StereoBM_GPU::PREFILTER_XSOBEL: - bm.preset = gpu::StereoBM_GPU::BASIC_PRESET; + case cv::StereoBM::PREFILTER_XSOBEL: + bm->setPreFilterType(0); break; } - cout << "prefilter_sobel: " << bm.preset << endl; + cout << "prefilter_sobel: " << bm->getPreFilterType() << endl; } break; case '1': p.ndisp = p.ndisp == 1 ? 8 : p.ndisp + 8; cout << "ndisp: " << p.ndisp << endl; - bm.ndisp = p.ndisp; + bm->setNumDisparities(p.ndisp); bp.ndisp = p.ndisp; csbp.ndisp = p.ndisp; break; case 'q': case 'Q': p.ndisp = max(p.ndisp - 8, 1); cout << "ndisp: " << p.ndisp << endl; - bm.ndisp = p.ndisp; + bm->setNumDisparities(p.ndisp); bp.ndisp = p.ndisp; csbp.ndisp = p.ndisp; break; case '2': if (p.method == Params::BM) { - bm.winSize = min(bm.winSize + 1, 51); - cout << "win_size: " << bm.winSize << endl; + bm->setBlockSize(min(bm->getBlockSize() + 1, 51)); + cout << "win_size: " << bm->getBlockSize() << endl; } break; case 'w': case 'W': if (p.method == Params::BM) { - bm.winSize = max(bm.winSize - 1, 2); - cout << "win_size: " << bm.winSize << endl; + bm->setBlockSize(max(bm->getBlockSize() - 1, 2)); + cout << "win_size: " << bm->getBlockSize() << endl; } break; case '3': diff --git a/samples/gpu/stereo_multi.cpp b/samples/gpu/stereo_multi.cpp index f85efe109e..1bb09b22bc 100644 --- a/samples/gpu/stereo_multi.cpp +++ b/samples/gpu/stereo_multi.cpp @@ -51,7 +51,7 @@ struct Worker { void operator()(int device_id) const; }; // GPUs data GpuMat d_left[2]; GpuMat d_right[2]; -StereoBM_GPU* bm[2]; +Ptr bm[2]; GpuMat d_result[2]; static void printHelp() @@ -112,13 +112,13 @@ int main(int argc, char** argv) setDevice(0); d_left[0].upload(left.rowRange(0, left.rows / 2)); d_right[0].upload(right.rowRange(0, right.rows / 2)); - bm[0] = new StereoBM_GPU(); + bm[0] = gpu::createStereoBM(); // Split source images for processing on the GPU #1 setDevice(1); d_left[1].upload(left.rowRange(left.rows / 2, left.rows)); d_right[1].upload(right.rowRange(right.rows / 2, right.rows)); - bm[1] = new StereoBM_GPU(); + bm[1] = gpu::createStereoBM(); // Execute calculation in two threads using two GPUs int devices[] = {0, 1}; @@ -130,7 +130,7 @@ int main(int argc, char** argv) d_left[0].release(); d_right[0].release(); d_result[0].release(); - delete bm[0]; + bm[0].release(); // Release the second GPU resources setDevice(1); @@ -138,7 +138,7 @@ int main(int argc, char** argv) d_left[1].release(); d_right[1].release(); d_result[1].release(); - delete bm[1]; + bm[1].release(); waitKey(); return 0; @@ -149,8 +149,7 @@ void Worker::operator()(int device_id) const { setDevice(device_id); - bm[device_id]->operator()(d_left[device_id], d_right[device_id], - d_result[device_id]); + bm[device_id]->compute(d_left[device_id], d_right[device_id], d_result[device_id]); std::cout << "GPU #" << device_id << " (" << DeviceInfo().name() << "): finished\n";