refactored StereoBM

This commit is contained in:
Vladislav Vinogradov 2013-05-08 14:27:56 +04:00
parent 71db862dc2
commit dd6d58f873
7 changed files with 139 additions and 116 deletions

View File

@ -48,44 +48,25 @@
#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 };
using cv::StereoBM::compute;
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());
//! 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();
int preset;
int ndisp;
int winSize;
// 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;
virtual void compute(InputArray left, InputArray right, OutputArray disparity, Stream& stream) = 0;
};
CV_EXPORTS Ptr<gpu::StereoBM> createStereoBM(int numDisparities = 64, int blockSize = 19);
// "Efficient Belief Propagation for Early Vision"
// P.Felzenszwalb
class CV_EXPORTS StereoBeliefPropagation

View File

@ -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<cv::StereoBM> 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);
}

View File

@ -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<gpu::StereoBM> cv::gpu::createStereoBM(int, int) { throw_no_cuda(); return Ptr<gpu::StereoBM>(); }
#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 );
disparity.create(left.size(), CV_8U);
minSSD.create(left.size(), CV_32S);
GpuMat left = _left.getGpuMat();
GpuMat right = _right.getGpuMat();
GpuMat le_for_bm = left;
GpuMat ri_for_bm = right;
CV_Assert( left.type() == CV_8UC1 );
CV_Assert( left.size() == right.size() && left.type() == right.type() );
if (preset == StereoBM_GPU::PREFILTER_XSOBEL)
_disparity.create(left.size(), CV_8UC1);
GpuMat disparity = _disparity.getGpuMat();
cudaStream_t stream = StreamAccessor::getStream(_stream);
gpu::ensureSizeIsEnough(left.size(), CV_32SC1, minSSD_);
PtrStepSzb le_for_bm = left;
PtrStepSzb ri_for_bm = right;
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<gpu::StereoBM> 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) */

View File

@ -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<cv::StereoBM> 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);
}

View File

@ -85,7 +85,7 @@ void inline contextOff()
// GPUs data
GpuMat d_left[2];
GpuMat d_right[2];
StereoBM_GPU* bm[2];
Ptr<gpu::StereoBM> 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";

View File

@ -65,7 +65,7 @@ private:
Mat left, right;
gpu::GpuMat d_left, d_right;
gpu::StereoBM_GPU bm;
Ptr<gpu::StereoBM> 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':

View File

@ -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<gpu::StereoBM> 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";