refactored StereoBM
This commit is contained in:
parent
71db862dc2
commit
dd6d58f873
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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':
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user