diff --git a/modules/gpustereo/include/opencv2/gpustereo.hpp b/modules/gpustereo/include/opencv2/gpustereo.hpp index 054504685..c20c6f79b 100644 --- a/modules/gpustereo/include/opencv2/gpustereo.hpp +++ b/modules/gpustereo/include/opencv2/gpustereo.hpp @@ -134,44 +134,48 @@ public: CV_EXPORTS Ptr createStereoConstantSpaceBP(int ndisp = 128, int iters = 8, int levels = 4, int nr_plane = 4, int msg_type = CV_32F); +///////////////////////////////////////// +// DisparityBilateralFilter - - -// Disparity map refinement using joint bilateral filtering given a single color image. -// Qingxiong Yang, Liang Wang, Narendra Ahuja -// http://vision.ai.uiuc.edu/~qyang6/ -class CV_EXPORTS DisparityBilateralFilter +//! Disparity map refinement using joint bilateral filtering given a single color image. +//! Qingxiong Yang, Liang Wang, Narendra Ahuja +//! http://vision.ai.uiuc.edu/~qyang6/ +class CV_EXPORTS DisparityBilateralFilter : public cv::Algorithm { public: - enum { DEFAULT_NDISP = 64 }; - enum { DEFAULT_RADIUS = 3 }; - enum { DEFAULT_ITERS = 1 }; - - //! the default constructor - explicit DisparityBilateralFilter(int ndisp = DEFAULT_NDISP, int radius = DEFAULT_RADIUS, int iters = DEFAULT_ITERS); - - //! the full constructor taking the number of disparities, filter radius, - //! number of iterations, truncation of data continuity, truncation of disparity continuity - //! and filter range sigma - DisparityBilateralFilter(int ndisp, int radius, int iters, float edge_threshold, float max_disc_threshold, float sigma_range); - //! the disparity map refinement operator. Refine disparity map using joint bilateral filtering given a single color image. //! disparity must have CV_8U or CV_16S type, image must have CV_8UC1 or CV_8UC3 type. - void operator()(const GpuMat& disparity, const GpuMat& image, GpuMat& dst, Stream& stream = Stream::Null()); + virtual void apply(InputArray disparity, InputArray image, OutputArray dst, Stream& stream = Stream::Null()) = 0; -private: - int ndisp; - int radius; - int iters; + virtual int getNumDisparities() const = 0; + virtual void setNumDisparities(int numDisparities) = 0; - float edge_threshold; - float max_disc_threshold; - float sigma_range; + virtual int getRadius() const = 0; + virtual void setRadius(int radius) = 0; - GpuMat table_color; - GpuMat table_space; + virtual int getNumIters() const = 0; + virtual void setNumIters(int iters) = 0; + + //! truncation of data continuity + virtual double getEdgeThreshold() const = 0; + virtual void setEdgeThreshold(double edge_threshold) = 0; + + //! truncation of disparity continuity + virtual double getMaxDiscThreshold() const = 0; + virtual void setMaxDiscThreshold(double max_disc_threshold) = 0; + + //! filter range sigma + virtual double getSigmaRange() const = 0; + virtual void setSigmaRange(double sigma_range) = 0; }; +CV_EXPORTS Ptr + createDisparityBilateralFilter(int ndisp = 64, int radius = 3, int iters = 1); + + + + + //! Reprojects disparity image to 3D space. //! Supports CV_8U and CV_16S types of input disparity. //! The output is a 3- or 4-channel floating-point matrix. diff --git a/modules/gpustereo/perf/perf_stereo.cpp b/modules/gpustereo/perf/perf_stereo.cpp index 276d97207..476a591a1 100644 --- a/modules/gpustereo/perf/perf_stereo.cpp +++ b/modules/gpustereo/perf/perf_stereo.cpp @@ -173,13 +173,13 @@ PERF_TEST_P(ImagePair, DisparityBilateralFilter, if (PERF_RUN_GPU()) { - cv::gpu::DisparityBilateralFilter d_filter(ndisp); + cv::Ptr d_filter = cv::gpu::createDisparityBilateralFilter(ndisp); const cv::gpu::GpuMat d_img(img); const cv::gpu::GpuMat d_disp(disp); cv::gpu::GpuMat dst; - TEST_CYCLE() d_filter(d_disp, d_img, dst); + TEST_CYCLE() d_filter->apply(d_disp, d_img, dst); GPU_SANITY_CHECK(dst); } diff --git a/modules/gpustereo/src/disparity_bilateral_filter.cpp b/modules/gpustereo/src/disparity_bilateral_filter.cpp index d13fcc004..689a9e76e 100644 --- a/modules/gpustereo/src/disparity_bilateral_filter.cpp +++ b/modules/gpustereo/src/disparity_bilateral_filter.cpp @@ -47,10 +47,7 @@ using namespace cv::gpu; #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) -cv::gpu::DisparityBilateralFilter::DisparityBilateralFilter(int, int, int) { throw_no_cuda(); } -cv::gpu::DisparityBilateralFilter::DisparityBilateralFilter(int, int, int, float, float, float) { throw_no_cuda(); } - -void cv::gpu::DisparityBilateralFilter::operator()(const GpuMat&, const GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); } +Ptr cv::gpu::createDisparityBilateralFilter(int, int, int) { throw_no_cuda(); return Ptr(); } #else /* !defined (HAVE_CUDA) */ @@ -65,15 +62,46 @@ namespace cv { namespace gpu { namespace cudev } }}} -using namespace ::cv::gpu::cudev::disp_bilateral_filter; - namespace { - const float DEFAULT_EDGE_THRESHOLD = 0.1f; - const float DEFAULT_MAX_DISC_THRESHOLD = 0.2f; - const float DEFAULT_SIGMA_RANGE = 10.0f; + class DispBilateralFilterImpl : public gpu::DisparityBilateralFilter + { + public: + DispBilateralFilterImpl(int ndisp, int radius, int iters); - inline void calc_color_weighted_table(GpuMat& table_color, float sigma_range, int len) + void apply(InputArray disparity, InputArray image, OutputArray dst, Stream& stream); + + int getNumDisparities() const { return ndisp_; } + void setNumDisparities(int numDisparities) { ndisp_ = numDisparities; } + + int getRadius() const { return radius_; } + void setRadius(int radius); + + int getNumIters() const { return iters_; } + void setNumIters(int iters) { iters_ = iters; } + + double getEdgeThreshold() const { return edge_threshold_; } + void setEdgeThreshold(double edge_threshold) { edge_threshold_ = (float) edge_threshold; } + + double getMaxDiscThreshold() const { return max_disc_threshold_; } + void setMaxDiscThreshold(double max_disc_threshold) { max_disc_threshold_ = (float) max_disc_threshold; } + + double getSigmaRange() const { return sigma_range_; } + void setSigmaRange(double sigma_range); + + private: + int ndisp_; + int radius_; + int iters_; + float edge_threshold_; + float max_disc_threshold_; + float sigma_range_; + + GpuMat table_color_; + GpuMat table_space_; + }; + + void calc_color_weighted_table(GpuMat& table_color, float sigma_range, int len) { Mat cpu_table_color(1, len, CV_32F); @@ -85,7 +113,7 @@ namespace table_color.upload(cpu_table_color); } - inline void calc_space_weighted_filter(GpuMat& table_space, int win_size, float dist_space) + void calc_space_weighted_filter(GpuMat& table_space, int win_size, float dist_space) { int half = (win_size >> 1); @@ -101,54 +129,78 @@ namespace table_space.upload(cpu_table_space); } - template - void disp_bilateral_filter_operator(int ndisp, int radius, int iters, float edge_threshold,float max_disc_threshold, - GpuMat& table_color, GpuMat& table_space, - const GpuMat& disp, const GpuMat& img, GpuMat& dst, Stream& stream) + const float DEFAULT_EDGE_THRESHOLD = 0.1f; + const float DEFAULT_MAX_DISC_THRESHOLD = 0.2f; + const float DEFAULT_SIGMA_RANGE = 10.0f; + + DispBilateralFilterImpl::DispBilateralFilterImpl(int ndisp, int radius, int iters) : + ndisp_(ndisp), radius_(radius), iters_(iters), + edge_threshold_(DEFAULT_EDGE_THRESHOLD), max_disc_threshold_(DEFAULT_MAX_DISC_THRESHOLD), + sigma_range_(DEFAULT_SIGMA_RANGE) { - short edge_disc = std::max(short(1), short(ndisp * edge_threshold + 0.5)); - short max_disc = short(ndisp * max_disc_threshold + 0.5); + calc_color_weighted_table(table_color_, sigma_range_, 255); + calc_space_weighted_filter(table_space_, radius_ * 2 + 1, radius_ + 1.0f); + } + + void DispBilateralFilterImpl::setRadius(int radius) + { + radius_ = radius; + calc_space_weighted_filter(table_space_, radius_ * 2 + 1, radius_ + 1.0f); + } + + void DispBilateralFilterImpl::setSigmaRange(double sigma_range) + { + sigma_range_ = (float) sigma_range; + calc_color_weighted_table(table_color_, sigma_range_, 255); + } + + template + void disp_bilateral_filter_operator(int ndisp, int radius, int iters, float edge_threshold, float max_disc_threshold, + GpuMat& table_color, GpuMat& table_space, + const GpuMat& disp, const GpuMat& img, + OutputArray _dst, Stream& stream) + { + using namespace cv::gpu::cudev::disp_bilateral_filter; + + const short edge_disc = std::max(short(1), short(ndisp * edge_threshold + 0.5)); + const short max_disc = short(ndisp * max_disc_threshold + 0.5); disp_load_constants(table_color.ptr(), table_space, ndisp, radius, edge_disc, max_disc); - if (&dst != &disp) - { + _dst.create(disp.size(), disp.type()); + GpuMat dst = _dst.getGpuMat(); + + if (dst.data != disp.data) disp.copyTo(dst, stream); - } disp_bilateral_filter(dst, img, img.channels(), iters, StreamAccessor::getStream(stream)); } - typedef void (*bilateral_filter_operator_t)(int ndisp, int radius, int iters, float edge_threshold, float max_disc_threshold, - GpuMat& table_color, GpuMat& table_space, - const GpuMat& disp, const GpuMat& img, GpuMat& dst, Stream& stream); + void DispBilateralFilterImpl::apply(InputArray _disp, InputArray _image, OutputArray dst, Stream& stream) + { + typedef void (*bilateral_filter_operator_t)(int ndisp, int radius, int iters, float edge_threshold, float max_disc_threshold, + GpuMat& table_color, GpuMat& table_space, + const GpuMat& disp, const GpuMat& img, OutputArray dst, Stream& stream); + const bilateral_filter_operator_t operators[] = + {disp_bilateral_filter_operator, 0, 0, disp_bilateral_filter_operator, 0, 0, 0, 0}; - const bilateral_filter_operator_t operators[] = - {disp_bilateral_filter_operator, 0, 0, disp_bilateral_filter_operator, 0, 0, 0, 0}; + CV_Assert( 0 < ndisp_ && 0 < radius_ && 0 < iters_ ); + + GpuMat disp = _disp.getGpuMat(); + GpuMat img = _image.getGpuMat(); + + CV_Assert( disp.type() == CV_8U || disp.type() == CV_16S ); + CV_Assert( img.type() == CV_8UC1 || img.type() == CV_8UC3 ); + CV_Assert( disp.size() == img.size() ); + + operators[disp.type()](ndisp_, radius_, iters_, edge_threshold_, max_disc_threshold_, + table_color_, table_space_, disp, img, dst, stream); + } } -cv::gpu::DisparityBilateralFilter::DisparityBilateralFilter(int ndisp_, int radius_, int iters_) - : ndisp(ndisp_), radius(radius_), iters(iters_), edge_threshold(DEFAULT_EDGE_THRESHOLD), max_disc_threshold(DEFAULT_MAX_DISC_THRESHOLD), - sigma_range(DEFAULT_SIGMA_RANGE) +Ptr cv::gpu::createDisparityBilateralFilter(int ndisp, int radius, int iters) { - calc_color_weighted_table(table_color, sigma_range, 255); - calc_space_weighted_filter(table_space, radius * 2 + 1, radius + 1.0f); -} - -cv::gpu::DisparityBilateralFilter::DisparityBilateralFilter(int ndisp_, int radius_, int iters_, float edge_threshold_, - float max_disc_threshold_, float sigma_range_) - : ndisp(ndisp_), radius(radius_), iters(iters_), edge_threshold(edge_threshold_), max_disc_threshold(max_disc_threshold_), - sigma_range(sigma_range_) -{ - calc_color_weighted_table(table_color, sigma_range, 255); - calc_space_weighted_filter(table_space, radius * 2 + 1, radius + 1.0f); -} - -void cv::gpu::DisparityBilateralFilter::operator()(const GpuMat& disp, const GpuMat& img, GpuMat& dst, Stream& stream) -{ - CV_DbgAssert(0 < ndisp && 0 < radius && 0 < iters); - CV_Assert(disp.rows == img.rows && disp.cols == img.cols && (disp.type() == CV_8U || disp.type() == CV_16S) && (img.type() == CV_8UC1 || img.type() == CV_8UC3)); - operators[disp.type()](ndisp, radius, iters, edge_threshold, max_disc_threshold, table_color, table_space, disp, img, dst, stream); + return new DispBilateralFilterImpl(ndisp, radius, iters); } #endif /* !defined (HAVE_CUDA) */