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