Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Third party copyrights are property of their respective owners.
     16 //
     17 // Redistribution and use in source and binary forms, with or without modification,
     18 // are permitted provided that the following conditions are met:
     19 //
     20 //   * Redistribution's of source code must retain the above copyright notice,
     21 //     this list of conditions and the following disclaimer.
     22 //
     23 //   * Redistribution's in binary form must reproduce the above copyright notice,
     24 //     this list of conditions and the following disclaimer in the documentation
     25 //     and/or other materials provided with the distribution.
     26 //
     27 //   * The name of the copyright holders may not be used to endorse or promote products
     28 //     derived from this software without specific prior written permission.
     29 //
     30 // This software is provided by the copyright holders and contributors "as is" and
     31 // any express or implied warranties, including, but not limited to, the implied
     32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     33 // In no event shall the Intel Corporation or contributors be liable for any direct,
     34 // indirect, incidental, special, exemplary, or consequential damages
     35 // (including, but not limited to, procurement of substitute goods or services;
     36 // loss of use, data, or profits; or business interruption) however caused
     37 // and on any theory of liability, whether in contract, strict liability,
     38 // or tort (including negligence or otherwise) arising in any way out of
     39 // the use of this software, even if advised of the possibility of such damage.
     40 //
     41 //M*/
     42 
     43 #include "precomp.hpp"
     44 
     45 using namespace cv;
     46 using namespace cv::cuda;
     47 
     48 #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
     49 
     50 void cv::cuda::StereoBeliefPropagation::estimateRecommendedParams(int, int, int&, int&, int&) { throw_no_cuda(); }
     51 
     52 Ptr<cuda::StereoBeliefPropagation> cv::cuda::createStereoBeliefPropagation(int, int, int, int) { throw_no_cuda(); return Ptr<cuda::StereoBeliefPropagation>(); }
     53 
     54 #else /* !defined (HAVE_CUDA) */
     55 
     56 namespace cv { namespace cuda { namespace device
     57 {
     58     namespace stereobp
     59     {
     60         void load_constants(int ndisp, float max_data_term, float data_weight, float max_disc_term, float disc_single_jump);
     61         template<typename T, typename D>
     62         void comp_data_gpu(const PtrStepSzb& left, const PtrStepSzb& right, const PtrStepSzb& data, cudaStream_t stream);
     63         template<typename T>
     64         void data_step_down_gpu(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream);
     65         template <typename T>
     66         void level_up_messages_gpu(int dst_idx, int dst_cols, int dst_rows, int src_rows, PtrStepSzb* mus, PtrStepSzb* mds, PtrStepSzb* mls, PtrStepSzb* mrs, cudaStream_t stream);
     67         template <typename T>
     68         void calc_all_iterations_gpu(int cols, int rows, int iters, const PtrStepSzb& u, const PtrStepSzb& d,
     69             const PtrStepSzb& l, const PtrStepSzb& r, const PtrStepSzb& data, cudaStream_t stream);
     70         template <typename T>
     71         void output_gpu(const PtrStepSzb& u, const PtrStepSzb& d, const PtrStepSzb& l, const PtrStepSzb& r, const PtrStepSzb& data,
     72             const PtrStepSz<short>& disp, cudaStream_t stream);
     73     }
     74 }}}
     75 
     76 namespace
     77 {
     78     class StereoBPImpl : public cuda::StereoBeliefPropagation
     79     {
     80     public:
     81         StereoBPImpl(int ndisp, int iters, int levels, int msg_type);
     82 
     83         void compute(InputArray left, InputArray right, OutputArray disparity);
     84         void compute(InputArray left, InputArray right, OutputArray disparity, Stream& stream);
     85         void compute(InputArray data, OutputArray disparity, Stream& stream);
     86 
     87         int getMinDisparity() const { return 0; }
     88         void setMinDisparity(int /*minDisparity*/) {}
     89 
     90         int getNumDisparities() const { return ndisp_; }
     91         void setNumDisparities(int numDisparities) { ndisp_ = numDisparities; }
     92 
     93         int getBlockSize() const { return 0; }
     94         void setBlockSize(int /*blockSize*/) {}
     95 
     96         int getSpeckleWindowSize() const { return 0; }
     97         void setSpeckleWindowSize(int /*speckleWindowSize*/) {}
     98 
     99         int getSpeckleRange() const { return 0; }
    100         void setSpeckleRange(int /*speckleRange*/) {}
    101 
    102         int getDisp12MaxDiff() const { return 0; }
    103         void setDisp12MaxDiff(int /*disp12MaxDiff*/) {}
    104 
    105         int getNumIters() const { return iters_; }
    106         void setNumIters(int iters) { iters_ = iters; }
    107 
    108         int getNumLevels() const { return levels_; }
    109         void setNumLevels(int levels) { levels_ = levels; }
    110 
    111         double getMaxDataTerm() const { return max_data_term_; }
    112         void setMaxDataTerm(double max_data_term) { max_data_term_ = (float) max_data_term; }
    113 
    114         double getDataWeight() const { return data_weight_; }
    115         void setDataWeight(double data_weight) { data_weight_ = (float) data_weight; }
    116 
    117         double getMaxDiscTerm() const { return max_disc_term_; }
    118         void setMaxDiscTerm(double max_disc_term) { max_disc_term_ = (float) max_disc_term; }
    119 
    120         double getDiscSingleJump() const { return disc_single_jump_; }
    121         void setDiscSingleJump(double disc_single_jump) { disc_single_jump_ = (float) disc_single_jump; }
    122 
    123         int getMsgType() const { return msg_type_; }
    124         void setMsgType(int msg_type) { msg_type_ = msg_type; }
    125 
    126     private:
    127         void init(Stream& stream);
    128         void calcBP(OutputArray disp, Stream& stream);
    129 
    130         int ndisp_;
    131         int iters_;
    132         int levels_;
    133         float max_data_term_;
    134         float data_weight_;
    135         float max_disc_term_;
    136         float disc_single_jump_;
    137         int msg_type_;
    138 
    139         float scale_;
    140         int rows_, cols_;
    141         std::vector<int> cols_all_, rows_all_;
    142         GpuMat u_, d_, l_, r_, u2_, d2_, l2_, r2_;
    143         std::vector<GpuMat> datas_;
    144         GpuMat outBuf_;
    145     };
    146 
    147     const float DEFAULT_MAX_DATA_TERM = 10.0f;
    148     const float DEFAULT_DATA_WEIGHT = 0.07f;
    149     const float DEFAULT_MAX_DISC_TERM = 1.7f;
    150     const float DEFAULT_DISC_SINGLE_JUMP = 1.0f;
    151 
    152     StereoBPImpl::StereoBPImpl(int ndisp, int iters, int levels, int msg_type) :
    153         ndisp_(ndisp), iters_(iters), levels_(levels),
    154         max_data_term_(DEFAULT_MAX_DATA_TERM), data_weight_(DEFAULT_DATA_WEIGHT),
    155         max_disc_term_(DEFAULT_MAX_DISC_TERM), disc_single_jump_(DEFAULT_DISC_SINGLE_JUMP),
    156         msg_type_(msg_type)
    157     {
    158     }
    159 
    160     void StereoBPImpl::compute(InputArray left, InputArray right, OutputArray disparity)
    161     {
    162         compute(left, right, disparity, Stream::Null());
    163     }
    164 
    165     void StereoBPImpl::compute(InputArray _left, InputArray _right, OutputArray disparity, Stream& stream)
    166     {
    167         using namespace cv::cuda::device::stereobp;
    168 
    169         typedef void (*comp_data_t)(const PtrStepSzb& left, const PtrStepSzb& right, const PtrStepSzb& data, cudaStream_t stream);
    170         static const comp_data_t comp_data_callers[2][5] =
    171         {
    172             {0, comp_data_gpu<unsigned char, short>, 0, comp_data_gpu<uchar3, short>, comp_data_gpu<uchar4, short>},
    173             {0, comp_data_gpu<unsigned char, float>, 0, comp_data_gpu<uchar3, float>, comp_data_gpu<uchar4, float>}
    174         };
    175 
    176         scale_ = msg_type_ == CV_32F ? 1.0f : 10.0f;
    177 
    178         CV_Assert( 0 < ndisp_ && 0 < iters_ && 0 < levels_ );
    179         CV_Assert( msg_type_ == CV_32F || msg_type_ == CV_16S );
    180         CV_Assert( msg_type_ == CV_32F || (1 << (levels_ - 1)) * scale_ * max_data_term_ < std::numeric_limits<short>::max() );
    181 
    182         GpuMat left = _left.getGpuMat();
    183         GpuMat right = _right.getGpuMat();
    184 
    185         CV_Assert( left.type() == CV_8UC1 || left.type() == CV_8UC3 || left.type() == CV_8UC4 );
    186         CV_Assert( left.size() == right.size() && left.type() == right.type() );
    187 
    188         rows_ = left.rows;
    189         cols_ = left.cols;
    190 
    191         const int divisor = (int) pow(2.f, levels_ - 1.0f);
    192         const int lowest_cols = cols_ / divisor;
    193         const int lowest_rows = rows_ / divisor;
    194         const int min_image_dim_size = 2;
    195         CV_Assert( std::min(lowest_cols, lowest_rows) > min_image_dim_size );
    196 
    197         init(stream);
    198 
    199         datas_[0].create(rows_ * ndisp_, cols_, msg_type_);
    200 
    201         comp_data_callers[msg_type_ == CV_32F][left.channels()](left, right, datas_[0], StreamAccessor::getStream(stream));
    202 
    203         calcBP(disparity, stream);
    204     }
    205 
    206     void StereoBPImpl::compute(InputArray _data, OutputArray disparity, Stream& stream)
    207     {
    208         scale_ = msg_type_ == CV_32F ? 1.0f : 10.0f;
    209 
    210         CV_Assert( 0 < ndisp_ && 0 < iters_ && 0 < levels_ );
    211         CV_Assert( msg_type_ == CV_32F || msg_type_ == CV_16S );
    212         CV_Assert( msg_type_ == CV_32F || (1 << (levels_ - 1)) * scale_ * max_data_term_ < std::numeric_limits<short>::max() );
    213 
    214         GpuMat data = _data.getGpuMat();
    215 
    216         CV_Assert( (data.type() == msg_type_) && (data.rows % ndisp_ == 0) );
    217 
    218         rows_ = data.rows / ndisp_;
    219         cols_ = data.cols;
    220 
    221         const int divisor = (int) pow(2.f, levels_ - 1.0f);
    222         const int lowest_cols = cols_ / divisor;
    223         const int lowest_rows = rows_ / divisor;
    224         const int min_image_dim_size = 2;
    225         CV_Assert( std::min(lowest_cols, lowest_rows) > min_image_dim_size );
    226 
    227         init(stream);
    228 
    229         data.copyTo(datas_[0], stream);
    230 
    231         calcBP(disparity, stream);
    232     }
    233 
    234     void StereoBPImpl::init(Stream& stream)
    235     {
    236         using namespace cv::cuda::device::stereobp;
    237 
    238         u_.create(rows_ * ndisp_, cols_, msg_type_);
    239         d_.create(rows_ * ndisp_, cols_, msg_type_);
    240         l_.create(rows_ * ndisp_, cols_, msg_type_);
    241         r_.create(rows_ * ndisp_, cols_, msg_type_);
    242 
    243         if (levels_ & 1)
    244         {
    245             //can clear less area
    246             u_.setTo(0, stream);
    247             d_.setTo(0, stream);
    248             l_.setTo(0, stream);
    249             r_.setTo(0, stream);
    250         }
    251 
    252         if (levels_ > 1)
    253         {
    254             int less_rows = (rows_ + 1) / 2;
    255             int less_cols = (cols_ + 1) / 2;
    256 
    257             u2_.create(less_rows * ndisp_, less_cols, msg_type_);
    258             d2_.create(less_rows * ndisp_, less_cols, msg_type_);
    259             l2_.create(less_rows * ndisp_, less_cols, msg_type_);
    260             r2_.create(less_rows * ndisp_, less_cols, msg_type_);
    261 
    262             if ((levels_ & 1) == 0)
    263             {
    264                 u2_.setTo(0, stream);
    265                 d2_.setTo(0, stream);
    266                 l2_.setTo(0, stream);
    267                 r2_.setTo(0, stream);
    268             }
    269         }
    270 
    271         load_constants(ndisp_, max_data_term_, scale_ * data_weight_, scale_ * max_disc_term_, scale_ * disc_single_jump_);
    272 
    273         datas_.resize(levels_);
    274 
    275         cols_all_.resize(levels_);
    276         rows_all_.resize(levels_);
    277 
    278         cols_all_[0] = cols_;
    279         rows_all_[0] = rows_;
    280     }
    281 
    282     void StereoBPImpl::calcBP(OutputArray disp, Stream& _stream)
    283     {
    284         using namespace cv::cuda::device::stereobp;
    285 
    286         typedef void (*data_step_down_t)(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream);
    287         static const data_step_down_t data_step_down_callers[2] =
    288         {
    289             data_step_down_gpu<short>, data_step_down_gpu<float>
    290         };
    291 
    292         typedef void (*level_up_messages_t)(int dst_idx, int dst_cols, int dst_rows, int src_rows, PtrStepSzb* mus, PtrStepSzb* mds, PtrStepSzb* mls, PtrStepSzb* mrs, cudaStream_t stream);
    293         static const level_up_messages_t level_up_messages_callers[2] =
    294         {
    295             level_up_messages_gpu<short>, level_up_messages_gpu<float>
    296         };
    297 
    298         typedef void (*calc_all_iterations_t)(int cols, int rows, int iters, const PtrStepSzb& u, const PtrStepSzb& d, const PtrStepSzb& l, const PtrStepSzb& r, const PtrStepSzb& data, cudaStream_t stream);
    299         static const calc_all_iterations_t calc_all_iterations_callers[2] =
    300         {
    301             calc_all_iterations_gpu<short>, calc_all_iterations_gpu<float>
    302         };
    303 
    304         typedef void (*output_t)(const PtrStepSzb& u, const PtrStepSzb& d, const PtrStepSzb& l, const PtrStepSzb& r, const PtrStepSzb& data, const PtrStepSz<short>& disp, cudaStream_t stream);
    305         static const output_t output_callers[2] =
    306         {
    307             output_gpu<short>, output_gpu<float>
    308         };
    309 
    310         const int funcIdx = msg_type_ == CV_32F;
    311 
    312         cudaStream_t stream = StreamAccessor::getStream(_stream);
    313 
    314         for (int i = 1; i < levels_; ++i)
    315         {
    316             cols_all_[i] = (cols_all_[i-1] + 1) / 2;
    317             rows_all_[i] = (rows_all_[i-1] + 1) / 2;
    318 
    319             datas_[i].create(rows_all_[i] * ndisp_, cols_all_[i], msg_type_);
    320 
    321             data_step_down_callers[funcIdx](cols_all_[i], rows_all_[i], rows_all_[i-1], datas_[i-1], datas_[i], stream);
    322         }
    323 
    324         PtrStepSzb mus[] = {u_, u2_};
    325         PtrStepSzb mds[] = {d_, d2_};
    326         PtrStepSzb mrs[] = {r_, r2_};
    327         PtrStepSzb mls[] = {l_, l2_};
    328 
    329         int mem_idx = (levels_ & 1) ? 0 : 1;
    330 
    331         for (int i = levels_ - 1; i >= 0; --i)
    332         {
    333             // for lower level we have already computed messages by setting to zero
    334             if (i != levels_ - 1)
    335                 level_up_messages_callers[funcIdx](mem_idx, cols_all_[i], rows_all_[i], rows_all_[i+1], mus, mds, mls, mrs, stream);
    336 
    337             calc_all_iterations_callers[funcIdx](cols_all_[i], rows_all_[i], iters_, mus[mem_idx], mds[mem_idx], mls[mem_idx], mrs[mem_idx], datas_[i], stream);
    338 
    339             mem_idx = (mem_idx + 1) & 1;
    340         }
    341 
    342         const int dtype = disp.fixedType() ? disp.type() : CV_16SC1;
    343 
    344         disp.create(rows_, cols_, dtype);
    345         GpuMat out = disp.getGpuMat();
    346 
    347         if (dtype != CV_16SC1)
    348         {
    349             outBuf_.create(rows_, cols_, CV_16SC1);
    350             out = outBuf_;
    351         }
    352 
    353         out.setTo(0, _stream);
    354 
    355         output_callers[funcIdx](u_, d_, l_, r_, datas_.front(), out, stream);
    356 
    357         if (dtype != CV_16SC1)
    358             out.convertTo(disp, dtype, _stream);
    359     }
    360 }
    361 
    362 Ptr<cuda::StereoBeliefPropagation> cv::cuda::createStereoBeliefPropagation(int ndisp, int iters, int levels, int msg_type)
    363 {
    364     return makePtr<StereoBPImpl>(ndisp, iters, levels, msg_type);
    365 }
    366 
    367 void cv::cuda::StereoBeliefPropagation::estimateRecommendedParams(int width, int height, int& ndisp, int& iters, int& levels)
    368 {
    369     ndisp = width / 4;
    370     if ((ndisp & 1) != 0)
    371         ndisp++;
    372 
    373     int mm = std::max(width, height);
    374     iters = mm / 100 + 2;
    375 
    376     levels = (int)(::log(static_cast<double>(mm)) + 1) * 4 / 5;
    377     if (levels == 0) levels++;
    378 }
    379 
    380 #endif /* !defined (HAVE_CUDA) */
    381