Merge pull request #258 from sbokov/AddingConfidence
Added confidence support to disparity filteringpull/287/head
commit
c05a7e0182
19 changed files with 2101 additions and 602 deletions
@ -0,0 +1,169 @@ |
||||
/*
|
||||
* By downloading, copying, installing or using the software you agree to this license. |
||||
* If you do not agree to this license, do not download, install, |
||||
* copy or use the software. |
||||
* |
||||
* |
||||
* License Agreement |
||||
* For Open Source Computer Vision Library |
||||
* (3 - clause BSD License) |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
* |
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
* |
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* This software is provided by the copyright holders and contributors "as is" and |
||||
* any express or implied warranties, including, but not limited to, the implied |
||||
* warranties of merchantability and fitness for a particular purpose are disclaimed. |
||||
* In no event shall copyright holders or contributors be liable for any direct, |
||||
* indirect, incidental, special, exemplary, or consequential damages |
||||
* (including, but not limited to, procurement of substitute goods or services; |
||||
* loss of use, data, or profits; or business interruption) however caused |
||||
* and on any theory of liability, whether in contract, strict liability, |
||||
* or tort(including negligence or otherwise) arising in any way out of |
||||
* the use of this software, even if advised of the possibility of such damage. |
||||
*/ |
||||
|
||||
#include "perf_precomp.hpp" |
||||
#include "opencv2/ximgproc/disparity_filter.hpp" |
||||
|
||||
namespace cvtest |
||||
{ |
||||
|
||||
using std::tr1::tuple; |
||||
using std::tr1::get; |
||||
using namespace perf; |
||||
using namespace testing; |
||||
using namespace cv; |
||||
using namespace cv::ximgproc; |
||||
|
||||
void MakeArtificialExample(RNG rng, Mat& dst_left_view, Mat& dst_left_disparity_map, Mat& dst_right_disparity_map, Rect& dst_ROI); |
||||
|
||||
CV_ENUM(GuideTypes, CV_8UC3); |
||||
CV_ENUM(SrcTypes, CV_16S); |
||||
typedef tuple<GuideTypes, SrcTypes, Size, bool, bool> DisparityWLSParams; |
||||
|
||||
typedef TestBaseWithParam<DisparityWLSParams> DisparityWLSFilterPerfTest; |
||||
|
||||
PERF_TEST_P( DisparityWLSFilterPerfTest, perf, Combine(GuideTypes::all(), SrcTypes::all(), Values(sz720p), Values(true,false), Values(true,false)) ) |
||||
{ |
||||
RNG rng(0); |
||||
|
||||
DisparityWLSParams params = GetParam(); |
||||
int guideType = get<0>(params); |
||||
int srcType = get<1>(params); |
||||
Size sz = get<2>(params); |
||||
bool use_conf = get<3>(params); |
||||
bool use_downscale = get<4>(params); |
||||
|
||||
Mat guide(sz, guideType); |
||||
Mat disp_left(sz, srcType); |
||||
Mat disp_right(sz, srcType); |
||||
Mat dst(sz, srcType); |
||||
Rect ROI; |
||||
|
||||
MakeArtificialExample(rng,guide,disp_left,disp_right,ROI); |
||||
if(use_downscale) |
||||
{ |
||||
resize(disp_left,disp_left,Size(),0.5,0.5); |
||||
disp_left/=2; |
||||
resize(disp_right,disp_right,Size(),0.5,0.5); |
||||
disp_right/=2; |
||||
ROI = Rect(ROI.x/2,ROI.y/2,ROI.width/2,ROI.height/2); |
||||
} |
||||
|
||||
cv::setNumThreads(cv::getNumberOfCPUs()); |
||||
TEST_CYCLE_N(10) |
||||
{ |
||||
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilter(use_conf); |
||||
wls_filter->filter(disp_left,guide,dst,ROI,disp_right); |
||||
} |
||||
|
||||
SANITY_CHECK(dst); |
||||
} |
||||
|
||||
void MakeArtificialExample(RNG rng, Mat& dst_left_view, Mat& dst_left_disparity_map, Mat& dst_right_disparity_map, Rect& dst_ROI) |
||||
{ |
||||
int w = dst_left_view.cols; |
||||
int h = dst_left_view.rows; |
||||
|
||||
//params:
|
||||
unsigned char bg_level = (unsigned char)rng.uniform(0.0,255.0); |
||||
unsigned char fg_level = (unsigned char)rng.uniform(0.0,255.0); |
||||
int rect_width = (int)rng.uniform(w/16,w/2); |
||||
int rect_height = (int)rng.uniform(h/16,h/2); |
||||
int rect_disparity = (int)(0.15*w); //typical maximum disparity value
|
||||
double sigma = 6.0; |
||||
|
||||
int rect_x_offset = (w-rect_width) /2; |
||||
int rect_y_offset = (h-rect_height)/2; |
||||
|
||||
if(dst_left_view.channels()==3) |
||||
dst_left_view = Scalar(Vec3b(bg_level,bg_level,bg_level)); |
||||
else |
||||
dst_left_view = Scalar(bg_level); |
||||
dst_left_disparity_map = Scalar(0); |
||||
dst_right_disparity_map = Scalar(0); |
||||
Mat dst_left_view_rect = Mat(dst_left_view, Rect(rect_x_offset,rect_y_offset,rect_width,rect_height)); |
||||
Mat dst_left_disparity_map_rect = Mat(dst_left_disparity_map,Rect(rect_x_offset,rect_y_offset,rect_width,rect_height)); |
||||
if(dst_left_view.channels()==3) |
||||
dst_left_view_rect = Scalar(Vec3b(fg_level,fg_level,fg_level)); |
||||
else |
||||
dst_left_view_rect = Scalar(fg_level); |
||||
dst_left_disparity_map_rect = Scalar(16*rect_disparity); |
||||
|
||||
rect_x_offset-=rect_disparity; |
||||
Mat dst_right_disparity_map_rect = Mat(dst_right_disparity_map,Rect(rect_x_offset,rect_y_offset,rect_width,rect_height)); |
||||
dst_right_disparity_map_rect = Scalar(-16*rect_disparity); |
||||
|
||||
//add some gaussian noise:
|
||||
unsigned char *l; |
||||
short *ldisp, *rdisp; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
l = dst_left_view.ptr(i); |
||||
ldisp = (short*)dst_left_disparity_map.ptr(i); |
||||
rdisp = (short*)dst_right_disparity_map.ptr(i); |
||||
|
||||
if(dst_left_view.channels()==3) |
||||
{ |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
l[0] = saturate_cast<unsigned char>(l[0] + rng.gaussian(sigma)); |
||||
l[1] = saturate_cast<unsigned char>(l[1] + rng.gaussian(sigma)); |
||||
l[2] = saturate_cast<unsigned char>(l[2] + rng.gaussian(sigma)); |
||||
l+=3; |
||||
ldisp[0] = saturate_cast<short>(ldisp[0] + rng.gaussian(sigma)); |
||||
ldisp++; |
||||
rdisp[0] = saturate_cast<short>(rdisp[0] + rng.gaussian(sigma)); |
||||
rdisp++; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
l[0] = saturate_cast<unsigned char>(l[0] + rng.gaussian(sigma)); |
||||
l++; |
||||
ldisp[0] = saturate_cast<short>(ldisp[0] + rng.gaussian(sigma)); |
||||
ldisp++; |
||||
rdisp[0] = saturate_cast<short>(rdisp[0] + rng.gaussian(sigma)); |
||||
rdisp++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
dst_ROI = Rect(rect_disparity,0,w-rect_disparity,h); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,81 @@ |
||||
/*
|
||||
* By downloading, copying, installing or using the software you agree to this license. |
||||
* If you do not agree to this license, do not download, install, |
||||
* copy or use the software. |
||||
* |
||||
* |
||||
* License Agreement |
||||
* For Open Source Computer Vision Library |
||||
* (3 - clause BSD License) |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
* |
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
* |
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* This software is provided by the copyright holders and contributors "as is" and |
||||
* any express or implied warranties, including, but not limited to, the implied |
||||
* warranties of merchantability and fitness for a particular purpose are disclaimed. |
||||
* In no event shall copyright holders or contributors be liable for any direct, |
||||
* indirect, incidental, special, exemplary, or consequential damages |
||||
* (including, but not limited to, procurement of substitute goods or services; |
||||
* loss of use, data, or profits; or business interruption) however caused |
||||
* and on any theory of liability, whether in contract, strict liability, |
||||
* or tort(including negligence or otherwise) arising in any way out of |
||||
* the use of this software, even if advised of the possibility of such damage. |
||||
*/ |
||||
|
||||
#include "perf_precomp.hpp" |
||||
|
||||
namespace cvtest |
||||
{ |
||||
|
||||
using std::tr1::tuple; |
||||
using std::tr1::get; |
||||
using namespace perf; |
||||
using namespace testing; |
||||
using namespace cv; |
||||
using namespace cv::ximgproc; |
||||
|
||||
CV_ENUM(GuideTypes, CV_8UC1, CV_8UC3); |
||||
CV_ENUM(SrcTypes, CV_8UC1, CV_8UC3, CV_16SC1, CV_16SC3, CV_32FC1, CV_32FC3); |
||||
typedef tuple<GuideTypes, SrcTypes, Size> FGSParams; |
||||
|
||||
typedef TestBaseWithParam<FGSParams> FGSFilterPerfTest; |
||||
|
||||
PERF_TEST_P( FGSFilterPerfTest, perf, Combine(GuideTypes::all(), SrcTypes::all(), Values(sz720p)) ) |
||||
{ |
||||
RNG rng(0); |
||||
|
||||
FGSParams params = GetParam(); |
||||
int guideType = get<0>(params); |
||||
int srcType = get<1>(params); |
||||
Size sz = get<2>(params); |
||||
|
||||
Mat guide(sz, guideType); |
||||
Mat src(sz, srcType); |
||||
Mat dst(sz, srcType); |
||||
|
||||
declare.in(guide, src, WARMUP_RNG).out(dst).tbb_threads(cv::getNumberOfCPUs()); |
||||
|
||||
cv::setNumThreads(cv::getNumberOfCPUs()); |
||||
TEST_CYCLE_N(10) |
||||
{ |
||||
double lambda = rng.uniform(500.0, 10000.0); |
||||
double sigma = rng.uniform(1.0, 100.0); |
||||
fastGlobalSmootherFilter(guide,src,dst,lambda,sigma); |
||||
} |
||||
|
||||
SANITY_CHECK(dst); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,694 @@ |
||||
/*
|
||||
* By downloading, copying, installing or using the software you agree to this license. |
||||
* If you do not agree to this license, do not download, install, |
||||
* copy or use the software. |
||||
* |
||||
* |
||||
* License Agreement |
||||
* For Open Source Computer Vision Library |
||||
* (3 - clause BSD License) |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
* |
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
* |
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* This software is provided by the copyright holders and contributors "as is" and |
||||
* any express or implied warranties, including, but not limited to, the implied |
||||
* warranties of merchantability and fitness for a particular purpose are disclaimed. |
||||
* In no event shall copyright holders or contributors be liable for any direct, |
||||
* indirect, incidental, special, exemplary, or consequential damages |
||||
* (including, but not limited to, procurement of substitute goods or services; |
||||
* loss of use, data, or profits; or business interruption) however caused |
||||
* and on any theory of liability, whether in contract, strict liability, |
||||
* or tort(including negligence or otherwise) arising in any way out of |
||||
* the use of this software, even if advised of the possibility of such damage. |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
#include "opencv2/hal/intrin.hpp" |
||||
#include <vector> |
||||
|
||||
namespace cv { |
||||
namespace ximgproc { |
||||
|
||||
using std::vector; |
||||
|
||||
typedef float WorkType; |
||||
typedef Vec<WorkType, 1> WorkVec; |
||||
typedef WorkType (*get_weight_op)(WorkType*, unsigned char*,unsigned char*); |
||||
|
||||
inline WorkType get_weight_1channel(WorkType* LUT, unsigned char* p1,unsigned char* p2) |
||||
{ |
||||
return LUT[ (p1[0]-p2[0])*(p1[0]-p2[0]) ]; |
||||
} |
||||
inline WorkType get_weight_3channel(WorkType* LUT, unsigned char* p1,unsigned char* p2) |
||||
{ |
||||
return LUT[ (p1[0]-p2[0])*(p1[0]-p2[0])+ |
||||
(p1[1]-p2[1])*(p1[1]-p2[1])+ |
||||
(p1[2]-p2[2])*(p1[2]-p2[2]) ]; |
||||
} |
||||
|
||||
class FastGlobalSmootherFilterImpl : public FastGlobalSmootherFilter |
||||
{ |
||||
public: |
||||
static Ptr<FastGlobalSmootherFilterImpl> create(InputArray guide, double lambda, double sigma_color, int num_iter,double lambda_attenuation); |
||||
void filter(InputArray src, OutputArray dst); |
||||
|
||||
protected: |
||||
int w,h; |
||||
int num_stripes; |
||||
float sigmaColor,lambda; |
||||
float lambda_attenuation; |
||||
int num_iter; |
||||
Mat weights_LUT; |
||||
Mat Chor, Cvert; |
||||
Mat interD; |
||||
void init(InputArray guide,double _lambda,double _sigmaColor,int _num_iter,double _lambda_attenuation); |
||||
void horizontalPass(Mat& cur); |
||||
void verticalPass(Mat& cur); |
||||
protected: |
||||
struct HorizontalPass_ParBody : public ParallelLoopBody |
||||
{ |
||||
FastGlobalSmootherFilterImpl* fgs; |
||||
Mat* cur; |
||||
int nstripes, stripe_sz; |
||||
int h; |
||||
|
||||
HorizontalPass_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _cur, int _nstripes, int _h); |
||||
void operator () (const Range& range) const; |
||||
}; |
||||
inline void process_4row_block(Mat* cur,int i); |
||||
inline void process_row(Mat* cur,int i); |
||||
|
||||
struct VerticalPass_ParBody : public ParallelLoopBody |
||||
{ |
||||
FastGlobalSmootherFilterImpl* fgs; |
||||
Mat* cur; |
||||
int nstripes, stripe_sz; |
||||
int w; |
||||
|
||||
VerticalPass_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _cur, int _nstripes, int _w); |
||||
void operator () (const Range& range) const; |
||||
}; |
||||
|
||||
template<get_weight_op get_weight, const int num_ch> |
||||
struct ComputeHorizontalWeights_ParBody : public ParallelLoopBody |
||||
{ |
||||
FastGlobalSmootherFilterImpl* fgs; |
||||
Mat* guide; |
||||
int nstripes, stripe_sz; |
||||
int h; |
||||
|
||||
ComputeHorizontalWeights_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _guide, int _nstripes, int _h); |
||||
void operator () (const Range& range) const; |
||||
}; |
||||
|
||||
template<get_weight_op get_weight, const int num_ch> |
||||
struct ComputeVerticalWeights_ParBody : public ParallelLoopBody |
||||
{ |
||||
FastGlobalSmootherFilterImpl* fgs; |
||||
Mat* guide; |
||||
int nstripes, stripe_sz; |
||||
int w; |
||||
|
||||
ComputeVerticalWeights_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _guide, int _nstripes, int _w); |
||||
void operator () (const Range& range) const; |
||||
}; |
||||
|
||||
struct ComputeLUT_ParBody : public ParallelLoopBody |
||||
{ |
||||
FastGlobalSmootherFilterImpl* fgs; |
||||
WorkType* LUT; |
||||
int nstripes, stripe_sz; |
||||
int sz; |
||||
|
||||
ComputeLUT_ParBody(FastGlobalSmootherFilterImpl &_fgs, WorkType* _LUT, int _nstripes, int _sz); |
||||
void operator () (const Range& range) const; |
||||
}; |
||||
}; |
||||
|
||||
|
||||
void FastGlobalSmootherFilterImpl::init(InputArray guide,double _lambda,double _sigmaColor,int _num_iter,double _lambda_attenuation) |
||||
{ |
||||
CV_Assert( !guide.empty() && _lambda >= 0 && _sigmaColor >= 0 && _num_iter >=1 ); |
||||
CV_Assert( guide.depth() == CV_8U && (guide.channels() == 1 || guide.channels() == 3) ); |
||||
sigmaColor = (float)_sigmaColor; |
||||
lambda = (float)_lambda; |
||||
lambda_attenuation = (float)_lambda_attenuation; |
||||
num_iter = _num_iter; |
||||
num_stripes = getNumThreads(); |
||||
int num_levels = 3*256*256; |
||||
weights_LUT.create(1,num_levels,WorkVec::type); |
||||
|
||||
WorkType* LUT = (WorkType*)weights_LUT.ptr(0); |
||||
parallel_for_(Range(0,num_stripes),ComputeLUT_ParBody(*this,LUT,num_stripes,num_levels)); |
||||
|
||||
w = guide.cols(); |
||||
h = guide.rows(); |
||||
Chor. create(h,w,WorkVec::type); |
||||
Cvert. create(h,w,WorkVec::type); |
||||
interD.create(h,w,WorkVec::type); |
||||
Mat guideMat = guide.getMat(); |
||||
|
||||
if(guide.channels() == 1) |
||||
{ |
||||
parallel_for_(Range(0,num_stripes),ComputeHorizontalWeights_ParBody<get_weight_1channel,1>(*this,guideMat,num_stripes,h)); |
||||
parallel_for_(Range(0,num_stripes),ComputeVerticalWeights_ParBody <get_weight_1channel,1>(*this,guideMat,num_stripes,w)); |
||||
} |
||||
if(guide.channels() == 3) |
||||
{ |
||||
parallel_for_(Range(0,num_stripes),ComputeHorizontalWeights_ParBody<get_weight_3channel,3>(*this,guideMat,num_stripes,h)); |
||||
parallel_for_(Range(0,num_stripes),ComputeVerticalWeights_ParBody <get_weight_3channel,3>(*this,guideMat,num_stripes,w)); |
||||
} |
||||
} |
||||
|
||||
Ptr<FastGlobalSmootherFilterImpl> FastGlobalSmootherFilterImpl::create(InputArray guide, double lambda, double sigma_color, int num_iter, double lambda_attenuation) |
||||
{ |
||||
FastGlobalSmootherFilterImpl *fgs = new FastGlobalSmootherFilterImpl(); |
||||
fgs->init(guide,lambda,sigma_color,num_iter,lambda_attenuation); |
||||
return Ptr<FastGlobalSmootherFilterImpl>(fgs); |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::filter(InputArray src, OutputArray dst) |
||||
{ |
||||
CV_Assert(!src.empty() && (src.depth() == CV_8U || src.depth() == CV_16S || src.depth() == CV_32F) && src.channels()<=4); |
||||
if (src.rows() != h || src.cols() != w) |
||||
{ |
||||
CV_Error(Error::StsBadSize, "Size of the filtered image must be equal to the size of the guide image"); |
||||
return; |
||||
} |
||||
|
||||
vector<Mat> src_channels; |
||||
vector<Mat> dst_channels; |
||||
if(src.channels()==1) |
||||
src_channels.push_back(src.getMat()); |
||||
else |
||||
split(src,src_channels); |
||||
|
||||
float lambda_ref = lambda; |
||||
|
||||
for(int i=0;i<src.channels();i++) |
||||
{ |
||||
lambda = lambda_ref; |
||||
Mat cur_res = src_channels[i].clone(); |
||||
if(src.depth()!=WorkVec::type) |
||||
cur_res.convertTo(cur_res,WorkVec::type); |
||||
|
||||
for(int n=0;n<num_iter;n++) |
||||
{ |
||||
horizontalPass(cur_res); |
||||
verticalPass(cur_res); |
||||
lambda*=lambda_attenuation; |
||||
} |
||||
|
||||
Mat dstMat; |
||||
if(src.depth()!=WorkVec::type) |
||||
cur_res.convertTo(dstMat,src.depth()); |
||||
else |
||||
dstMat = cur_res; |
||||
|
||||
dst_channels.push_back(dstMat); |
||||
} |
||||
|
||||
lambda = lambda_ref; |
||||
|
||||
dst.create(src.size(),src.type()); |
||||
if(src.channels()==1) |
||||
{ |
||||
Mat& dstMat = dst.getMatRef(); |
||||
dstMat = dst_channels[0]; |
||||
} |
||||
else |
||||
merge(dst_channels,dst); |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::horizontalPass(Mat& cur) |
||||
{ |
||||
parallel_for_(Range(0,num_stripes),HorizontalPass_ParBody(*this,cur,num_stripes,h)); |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::verticalPass(Mat& cur) |
||||
{ |
||||
parallel_for_(Range(0,num_stripes),VerticalPass_ParBody(*this,cur,num_stripes,w)); |
||||
} |
||||
|
||||
FastGlobalSmootherFilterImpl::HorizontalPass_ParBody::HorizontalPass_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _cur, int _nstripes, int _h): |
||||
fgs(&_fgs),cur(&_cur), nstripes(_nstripes), h(_h) |
||||
{ |
||||
stripe_sz = (int)ceil(h/(double)nstripes); |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::process_4row_block(Mat* cur,int i) |
||||
{ |
||||
WorkType denom,denom_next,denom_next2,denom_next3; |
||||
|
||||
WorkType *Chor_row = (WorkType*)Chor.ptr (i); |
||||
WorkType *interD_row = (WorkType*)interD.ptr(i); |
||||
WorkType *cur_row = (WorkType*)cur->ptr (i); |
||||
|
||||
WorkType *Chor_row_next = (WorkType*)Chor.ptr (i+1); |
||||
WorkType *interD_row_next = (WorkType*)interD.ptr(i+1); |
||||
WorkType *cur_row_next = (WorkType*)cur->ptr (i+1); |
||||
|
||||
WorkType *Chor_row_next2 = (WorkType*)Chor.ptr (i+2); |
||||
WorkType *interD_row_next2 = (WorkType*)interD.ptr(i+2); |
||||
WorkType *cur_row_next2 = (WorkType*)cur->ptr (i+2); |
||||
|
||||
WorkType *Chor_row_next3 = (WorkType*)Chor.ptr (i+3); |
||||
WorkType *interD_row_next3 = (WorkType*)interD.ptr(i+3); |
||||
WorkType *cur_row_next3 = (WorkType*)cur->ptr (i+3); |
||||
|
||||
float coef_cur, coef_prev; |
||||
float coef_cur_row_next, coef_prev_row_next; |
||||
float coef_cur_row_next2,coef_prev_row_next2; |
||||
float coef_cur_row_next3,coef_prev_row_next3; |
||||
|
||||
//forward pass:
|
||||
coef_prev = lambda*Chor_row[0]; |
||||
coef_prev_row_next = lambda*Chor_row_next[0]; |
||||
coef_prev_row_next2 = lambda*Chor_row_next2[0]; |
||||
coef_prev_row_next3 = lambda*Chor_row_next3[0]; |
||||
|
||||
interD_row[0] = coef_prev /(1-coef_prev); |
||||
interD_row_next[0] = coef_prev_row_next /(1-coef_prev_row_next); |
||||
interD_row_next2[0] = coef_prev_row_next2/(1-coef_prev_row_next2); |
||||
interD_row_next3[0] = coef_prev_row_next3/(1-coef_prev_row_next3); |
||||
|
||||
cur_row[0] = cur_row[0] /(1-coef_prev); |
||||
cur_row_next[0] = cur_row_next[0] /(1-coef_prev_row_next); |
||||
cur_row_next2[0] = cur_row_next2[0]/(1-coef_prev_row_next2); |
||||
cur_row_next3[0] = cur_row_next3[0]/(1-coef_prev_row_next3); |
||||
int j=1; |
||||
|
||||
#if CV_SIMD128 |
||||
{ |
||||
v_float32x4 coef_prev_reg(coef_prev,coef_prev_row_next,coef_prev_row_next2,coef_prev_row_next3); |
||||
v_float32x4 interD_prev_reg(interD_row[0],interD_row_next[0],interD_row_next2[0],interD_row_next3[0]); |
||||
v_float32x4 cur_prev_reg(cur_row[0],cur_row_next[0],cur_row_next2[0],cur_row_next3[0]); |
||||
v_float32x4 lambda_reg(lambda,lambda,lambda,lambda); |
||||
v_float32x4 one_reg(1.0f,1.0f,1.0f,1.0f); |
||||
|
||||
v_float32x4 a0,a1,a2,a3; |
||||
v_float32x4 b0,b1,b2,b3; |
||||
v_float32x4 aux0,aux1,aux2,aux3; |
||||
|
||||
#define PROC4(Chor_in,cur_in,coef_prev_in,interD_prev_in,cur_prev_in,interD_out,cur_out,coef_cur_out)\ |
||||
coef_cur_out = lambda_reg*Chor_in;\
|
||||
aux0 = interD_prev_in*coef_prev_in;\
|
||||
aux1 = coef_cur_out+coef_prev_in;\
|
||||
aux1 = one_reg-aux1;\
|
||||
aux0 = aux1-aux0;\
|
||||
interD_out = coef_cur_out/aux0;\
|
||||
aux1 = cur_prev_in*coef_prev_in;\
|
||||
aux1 = cur_in - aux1;\
|
||||
cur_out = aux1/aux0; |
||||
|
||||
for(;j<w-3;j+=4) |
||||
{ |
||||
// processing a 4x4 block:
|
||||
|
||||
aux0 = v_load(Chor_row+j); |
||||
aux1 = v_load(Chor_row_next+j); |
||||
aux2 = v_load(Chor_row_next2+j); |
||||
aux3 = v_load(Chor_row_next3+j); |
||||
v_transpose4x4(aux0,aux1,aux2,aux3,a0,a1,a2,a3); |
||||
|
||||
aux0 = v_load(cur_row+j); |
||||
aux1 = v_load(cur_row_next+j); |
||||
aux2 = v_load(cur_row_next2+j); |
||||
aux3 = v_load(cur_row_next3+j); |
||||
v_transpose4x4(aux0,aux1,aux2,aux3,b0,b1,b2,b3); |
||||
|
||||
PROC4(a0,b0,coef_prev_reg,interD_prev_reg,cur_prev_reg,a0,b0,aux2); |
||||
PROC4(a1,b1,aux2,a0,b0,a1,b1,aux3); |
||||
PROC4(a2,b2,aux3,a1,b1,a2,b2,aux2); |
||||
PROC4(a3,b3,aux2,a2,b2,a3,b3,aux3); |
||||
|
||||
interD_prev_reg = a3; |
||||
cur_prev_reg = b3; |
||||
coef_prev_reg = aux3; |
||||
|
||||
v_transpose4x4(a0,a1,a2,a3,aux0,aux1,aux2,aux3); |
||||
v_store(interD_row+j,aux0); |
||||
v_store(interD_row_next+j,aux1); |
||||
v_store(interD_row_next2+j,aux2); |
||||
v_store(interD_row_next3+j,aux3); |
||||
|
||||
v_transpose4x4(b0,b1,b2,b3,aux0,aux1,aux2,aux3); |
||||
v_store(cur_row+j,aux0); |
||||
v_store(cur_row_next+j,aux1); |
||||
v_store(cur_row_next2+j,aux2); |
||||
v_store(cur_row_next3+j,aux3); |
||||
} |
||||
#undef PROC4 |
||||
} |
||||
#endif |
||||
|
||||
for(;j<w;j++) |
||||
{ |
||||
coef_prev = lambda*Chor_row[j-1]; |
||||
coef_prev_row_next = lambda*Chor_row_next[j-1]; |
||||
coef_prev_row_next2 = lambda*Chor_row_next2[j-1]; |
||||
coef_prev_row_next3 = lambda*Chor_row_next3[j-1]; |
||||
|
||||
coef_cur = lambda*Chor_row[j]; |
||||
coef_cur_row_next = lambda*Chor_row_next[j]; |
||||
coef_cur_row_next2 = lambda*Chor_row_next2[j]; |
||||
coef_cur_row_next3 = lambda*Chor_row_next3[j]; |
||||
|
||||
denom = (1-coef_prev -coef_cur) -interD_row[j-1] *coef_prev; |
||||
denom_next = (1-coef_prev_row_next -coef_cur_row_next) -interD_row_next[j-1] *coef_prev_row_next; |
||||
denom_next2 = (1-coef_prev_row_next2-coef_cur_row_next2)-interD_row_next2[j-1]*coef_prev_row_next2; |
||||
denom_next3 = (1-coef_prev_row_next3-coef_cur_row_next3)-interD_row_next3[j-1]*coef_prev_row_next3; |
||||
|
||||
interD_row[j] = coef_cur /denom; |
||||
interD_row_next[j] = coef_cur_row_next /denom_next; |
||||
interD_row_next2[j] = coef_cur_row_next2/denom_next2; |
||||
interD_row_next3[j] = coef_cur_row_next3/denom_next3; |
||||
|
||||
cur_row[j] = (cur_row[j] -cur_row[j-1] *coef_prev) /denom; |
||||
cur_row_next[j] = (cur_row_next[j] -cur_row_next[j-1] *coef_prev_row_next) /denom_next; |
||||
cur_row_next2[j] = (cur_row_next2[j]-cur_row_next2[j-1]*coef_prev_row_next2)/denom_next2; |
||||
cur_row_next3[j] = (cur_row_next3[j]-cur_row_next3[j-1]*coef_prev_row_next3)/denom_next3; |
||||
} |
||||
//backward pass:
|
||||
j = w-2; |
||||
|
||||
#if CV_SIMD128 |
||||
{ |
||||
v_float32x4 cur_next_reg(cur_row[w-1],cur_row_next[w-1],cur_row_next2[w-1],cur_row_next3[w-1]); |
||||
v_float32x4 a0,a1,a2,a3; |
||||
v_float32x4 b0,b1,b2,b3; |
||||
v_float32x4 aux0,aux1,aux2,aux3; |
||||
for(j-=3;j>=0;j-=4) |
||||
{ |
||||
//process 4x4 block:
|
||||
|
||||
aux0 = v_load(interD_row+j); |
||||
aux1 = v_load(interD_row_next+j); |
||||
aux2 = v_load(interD_row_next2+j); |
||||
aux3 = v_load(interD_row_next3+j); |
||||
v_transpose4x4(aux0,aux1,aux2,aux3,a0,a1,a2,a3); |
||||
|
||||
aux0 = v_load(cur_row+j); |
||||
aux1 = v_load(cur_row_next+j); |
||||
aux2 = v_load(cur_row_next2+j); |
||||
aux3 = v_load(cur_row_next3+j); |
||||
v_transpose4x4(aux0,aux1,aux2,aux3,b0,b1,b2,b3); |
||||
|
||||
aux0 = a3*cur_next_reg; |
||||
b3 = b3-aux0; |
||||
aux0 = a2*b3; |
||||
b2 = b2-aux0; |
||||
aux0 = a1*b2; |
||||
b1 = b1-aux0; |
||||
aux0 = a0*b1; |
||||
b0 = b0-aux0; |
||||
|
||||
cur_next_reg = b0; |
||||
|
||||
v_transpose4x4(b0,b1,b2,b3,aux0,aux1,aux2,aux3); |
||||
v_store(cur_row+j,aux0); |
||||
v_store(cur_row_next+j,aux1); |
||||
v_store(cur_row_next2+j,aux2); |
||||
v_store(cur_row_next3+j,aux3); |
||||
} |
||||
j+=3; |
||||
} |
||||
#endif |
||||
|
||||
for(;j>=0;j--) |
||||
{ |
||||
cur_row[j] = cur_row[j] -interD_row[j] *cur_row[j+1]; |
||||
cur_row_next[j] = cur_row_next[j] -interD_row_next[j] *cur_row_next[j+1]; |
||||
cur_row_next2[j] = cur_row_next2[j]-interD_row_next2[j]*cur_row_next2[j+1]; |
||||
cur_row_next3[j] = cur_row_next3[j]-interD_row_next3[j]*cur_row_next3[j+1]; |
||||
} |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::process_row(Mat* cur,int i) |
||||
{ |
||||
WorkType denom; |
||||
WorkType *Chor_row = (WorkType*)Chor.ptr(i); |
||||
WorkType *interD_row = (WorkType*)interD.ptr(i); |
||||
WorkType *cur_row = (WorkType*)cur->ptr(i); |
||||
|
||||
float coef_cur,coef_prev; |
||||
|
||||
//forward pass:
|
||||
coef_prev = lambda*Chor_row[0]; |
||||
interD_row[0] = coef_prev/(1-coef_prev); |
||||
cur_row[0] = cur_row[0]/(1-coef_prev); |
||||
for(int j=1;j<w;j++) |
||||
{ |
||||
coef_cur = lambda*Chor_row[j]; |
||||
denom = (1-coef_prev-coef_cur)-interD_row[j-1]*coef_prev; |
||||
interD_row[j] = coef_cur/denom; |
||||
cur_row[j] = (cur_row[j]-cur_row[j-1]*coef_prev)/denom; |
||||
coef_prev = coef_cur; |
||||
} |
||||
|
||||
//backward pass:
|
||||
for(int j=w-2;j>=0;j--) |
||||
cur_row[j] = cur_row[j]-interD_row[j]*cur_row[j+1]; |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::HorizontalPass_ParBody::operator()(const Range& range) const |
||||
{ |
||||
int start = std::min(range.start * stripe_sz, h); |
||||
int end = std::min(range.end * stripe_sz, h); |
||||
|
||||
int i=start; |
||||
for(;i<end-3;i+=4) |
||||
fgs->process_4row_block(cur,i); |
||||
for(;i<end;i++) |
||||
fgs->process_row(cur,i); |
||||
} |
||||
|
||||
FastGlobalSmootherFilterImpl::VerticalPass_ParBody::VerticalPass_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _cur, int _nstripes, int _w): |
||||
fgs(&_fgs),cur(&_cur), nstripes(_nstripes), w(_w) |
||||
{ |
||||
stripe_sz = (int)ceil(w/(double)nstripes); |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::VerticalPass_ParBody::operator()(const Range& range) const |
||||
{ |
||||
int start = std::min(range.start * stripe_sz, w); |
||||
int end = std::min(range.end * stripe_sz, w); |
||||
|
||||
//float lambda = fgs->lambda;
|
||||
WorkType denom; |
||||
WorkType *Cvert_row, *Cvert_row_prev; |
||||
WorkType *interD_row, *interD_row_prev, *cur_row, *cur_row_prev, *cur_row_next; |
||||
|
||||
float coef_cur,coef_prev; |
||||
|
||||
Cvert_row = (WorkType*)fgs->Cvert.ptr(0); |
||||
interD_row = (WorkType*)fgs->interD.ptr(0); |
||||
cur_row = (WorkType*)cur->ptr(0); |
||||
//forward pass:
|
||||
for(int j=start;j<end;j++) |
||||
{ |
||||
coef_cur = fgs->lambda*Cvert_row[j]; |
||||
interD_row[j] = coef_cur/(1-coef_cur); |
||||
cur_row[j] = cur_row[j]/(1-coef_cur); |
||||
} |
||||
for(int i=1;i<fgs->h;i++) |
||||
{ |
||||
Cvert_row = (WorkType*)fgs->Cvert.ptr(i); |
||||
Cvert_row_prev = (WorkType*)fgs->Cvert.ptr(i-1); |
||||
interD_row = (WorkType*)fgs->interD.ptr(i); |
||||
interD_row_prev = (WorkType*)fgs->interD.ptr(i-1); |
||||
cur_row = (WorkType*)cur->ptr(i); |
||||
cur_row_prev = (WorkType*)cur->ptr(i-1); |
||||
int j = start; |
||||
|
||||
#if CV_SIMD128 |
||||
v_float32x4 a,b,c,d,coef_cur_reg,coef_prev_reg; |
||||
v_float32x4 one_reg(1.0f,1.0f,1.0f,1.0f); |
||||
v_float32x4 lambda_reg(fgs->lambda,fgs->lambda,fgs->lambda,fgs->lambda); |
||||
int sz4 = 4*((end-start)/4); |
||||
int end4 = start+sz4; |
||||
for(;j<end4;j+=4) |
||||
{ |
||||
a = v_load(Cvert_row_prev+j); |
||||
b = v_load(Cvert_row+j); |
||||
coef_prev_reg = lambda_reg*a; |
||||
coef_cur_reg = lambda_reg*b; |
||||
|
||||
a = v_load(interD_row_prev+j); |
||||
a = a*coef_prev_reg; |
||||
|
||||
b = coef_prev_reg+coef_cur_reg; |
||||
b = b+a; |
||||
a = one_reg-b; //computed denom
|
||||
|
||||
b = coef_cur_reg/a; //computed interD_row
|
||||
|
||||
c = v_load(cur_row_prev+j); |
||||
c = c*coef_prev_reg; |
||||
|
||||
d = v_load(cur_row+j); |
||||
d = d-c; |
||||
d = d/a; //computed cur_row
|
||||
|
||||
v_store(interD_row+j,b); |
||||
v_store(cur_row+j,d); |
||||
} |
||||
#endif |
||||
for(;j<end;j++) |
||||
{ |
||||
coef_prev = fgs->lambda*Cvert_row_prev[j]; |
||||
coef_cur = fgs->lambda*Cvert_row[j]; |
||||
denom = (1-coef_prev-coef_cur)-interD_row_prev[j]*coef_prev; |
||||
interD_row[j] = coef_cur/denom; |
||||
cur_row[j] = (cur_row[j]-cur_row_prev[j]*coef_prev)/denom; |
||||
} |
||||
} |
||||
|
||||
//backward pass:
|
||||
for(int i=fgs->h-2;i>=0;i--) |
||||
{ |
||||
interD_row = (WorkType*)fgs->interD.ptr(i); |
||||
cur_row = (WorkType*)cur->ptr(i); |
||||
cur_row_next = (WorkType*)cur->ptr(i+1); |
||||
int j = start; |
||||
#if CV_SIMD128 |
||||
v_float32x4 a,b; |
||||
int sz4 = 4*((end-start)/4); |
||||
int end4 = start+sz4; |
||||
for(;j<end4;j+=4) |
||||
{ |
||||
a = v_load(interD_row+j); |
||||
b = v_load(cur_row_next+j); |
||||
b = a*b; |
||||
|
||||
a = v_load(cur_row+j); |
||||
b = a-b; |
||||
v_store(cur_row+j,b); |
||||
} |
||||
#endif |
||||
for(;j<end;j++) |
||||
cur_row[j] = cur_row[j]-interD_row[j]*cur_row_next[j]; |
||||
} |
||||
} |
||||
|
||||
template<get_weight_op get_weight, const int num_ch> |
||||
FastGlobalSmootherFilterImpl::ComputeHorizontalWeights_ParBody<get_weight,num_ch>::ComputeHorizontalWeights_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _guide, int _nstripes, int _h): |
||||
fgs(&_fgs),guide(&_guide), nstripes(_nstripes), h(_h) |
||||
{ |
||||
stripe_sz = (int)ceil(h/(double)nstripes); |
||||
} |
||||
|
||||
template<get_weight_op get_weight, const int num_ch> |
||||
void FastGlobalSmootherFilterImpl::ComputeHorizontalWeights_ParBody<get_weight,num_ch>::operator()(const Range& range) const |
||||
{ |
||||
int start = std::min(range.start * stripe_sz, h); |
||||
int end = std::min(range.end * stripe_sz, h); |
||||
|
||||
WorkType* LUT = (WorkType*)fgs->weights_LUT.ptr(0); |
||||
unsigned char *row; |
||||
WorkType *Chor_row; |
||||
|
||||
for(int i=start;i<end;i++) |
||||
{ |
||||
row = guide->ptr(i); |
||||
Chor_row = (WorkType*)fgs->Chor.ptr(i); |
||||
Chor_row[0] = get_weight(LUT,row,row+num_ch); |
||||
row+=num_ch; |
||||
for(int j=1;j<fgs->w-1;j++) |
||||
{ |
||||
Chor_row[j] = get_weight(LUT,row,row+num_ch); |
||||
row+=num_ch; |
||||
} |
||||
Chor_row[fgs->w-1]=0; |
||||
} |
||||
} |
||||
|
||||
template<get_weight_op get_weight, const int num_ch> |
||||
FastGlobalSmootherFilterImpl::ComputeVerticalWeights_ParBody<get_weight,num_ch>::ComputeVerticalWeights_ParBody(FastGlobalSmootherFilterImpl &_fgs, Mat& _guide, int _nstripes, int _w): |
||||
fgs(&_fgs),guide(&_guide), nstripes(_nstripes), w(_w) |
||||
{ |
||||
stripe_sz = (int)ceil(w/(double)nstripes); |
||||
} |
||||
|
||||
template<get_weight_op get_weight, const int num_ch> |
||||
void FastGlobalSmootherFilterImpl::ComputeVerticalWeights_ParBody<get_weight,num_ch>::operator()(const Range& range) const |
||||
{ |
||||
int start = std::min(range.start * stripe_sz, w); |
||||
int end = std::min(range.end * stripe_sz, w); |
||||
|
||||
WorkType* LUT = (WorkType*)fgs->weights_LUT.ptr(0); |
||||
unsigned char *row,*row_next; |
||||
WorkType *Cvert_row; |
||||
|
||||
Cvert_row = (WorkType*)fgs->Cvert.ptr(0); |
||||
row = guide->ptr(0)+start*num_ch; |
||||
row_next = guide->ptr(1)+start*num_ch; |
||||
for(int j=start;j<end;j++) |
||||
{ |
||||
Cvert_row[j] = get_weight(LUT,row,row_next); |
||||
row+=num_ch; |
||||
row_next+=num_ch; |
||||
} |
||||
|
||||
for(int i=1;i<fgs->h-1;i++) |
||||
{ |
||||
row = guide->ptr(i)+start*num_ch; |
||||
row_next = guide->ptr(i+1)+start*num_ch; |
||||
Cvert_row = (WorkType*)fgs->Cvert.ptr(i); |
||||
for(int j=start;j<end;j++) |
||||
{ |
||||
Cvert_row[j] = get_weight(LUT,row,row_next); |
||||
row+=num_ch; |
||||
row_next+=num_ch; |
||||
} |
||||
} |
||||
|
||||
Cvert_row = (WorkType*)fgs->Cvert.ptr(fgs->h-1); |
||||
for(int j=start;j<end;j++) |
||||
Cvert_row[j] = 0; |
||||
} |
||||
|
||||
FastGlobalSmootherFilterImpl::ComputeLUT_ParBody::ComputeLUT_ParBody(FastGlobalSmootherFilterImpl &_fgs, WorkType *_LUT, int _nstripes, int _sz): |
||||
fgs(&_fgs), LUT(_LUT), nstripes(_nstripes), sz(_sz) |
||||
{ |
||||
stripe_sz = (int)ceil(sz/(double)nstripes); |
||||
} |
||||
|
||||
void FastGlobalSmootherFilterImpl::ComputeLUT_ParBody::operator()(const Range& range) const |
||||
{ |
||||
int start = std::min(range.start * stripe_sz, sz); |
||||
int end = std::min(range.end * stripe_sz, sz); |
||||
for(int i=start;i<end;i++) |
||||
LUT[i] = (WorkType)(-cv::exp(-sqrt((float)i)/fgs->sigmaColor)); |
||||
} |
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<FastGlobalSmootherFilter> createFastGlobalSmootherFilter(InputArray guide, double lambda, double sigma_color, double lambda_attenuation, int num_iter) |
||||
{ |
||||
return Ptr<FastGlobalSmootherFilter>(FastGlobalSmootherFilterImpl::create(guide, lambda, sigma_color, num_iter, lambda_attenuation)); |
||||
} |
||||
|
||||
CV_EXPORTS_W |
||||
void fastGlobalSmootherFilter(InputArray guide, InputArray src, OutputArray dst, double lambda, double sigma_color, double lambda_attenuation, int num_iter) |
||||
{ |
||||
Ptr<FastGlobalSmootherFilter> fgs = createFastGlobalSmootherFilter(guide, lambda, sigma_color, lambda_attenuation, num_iter); |
||||
fgs->filter(src, dst); |
||||
} |
||||
|
||||
} |
||||
} |
@ -1,284 +0,0 @@ |
||||
/*
|
||||
* By downloading, copying, installing or using the software you agree to this license. |
||||
* If you do not agree to this license, do not download, install, |
||||
* copy or use the software. |
||||
*
|
||||
*
|
||||
* License Agreement |
||||
* For Open Source Computer Vision Library |
||||
* (3 - clause BSD License) |
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
*
|
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
*
|
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
*
|
||||
* This software is provided by the copyright holders and contributors "as is" and |
||||
* any express or implied warranties, including, but not limited to, the implied |
||||
* warranties of merchantability and fitness for a particular purpose are disclaimed. |
||||
* In no event shall copyright holders or contributors be liable for any direct, |
||||
* indirect, incidental, special, exemplary, or consequential damages |
||||
* (including, but not limited to, procurement of substitute goods or services; |
||||
* loss of use, data, or profits; or business interruption) however caused |
||||
* and on any theory of liability, whether in contract, strict liability, |
||||
* or tort(including negligence or otherwise) arising in any way out of |
||||
* the use of this software, even if advised of the possibility of such damage. |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
namespace cv { |
||||
namespace ximgproc { |
||||
|
||||
class WeightedLeastSquaresFilterImpl : public WeightedLeastSquaresFilter |
||||
{ |
||||
public: |
||||
static Ptr<WeightedLeastSquaresFilterImpl> create(InputArray guide, double lambda, double sigma_color, int num_iter); |
||||
void filter(InputArray src, OutputArray dst); |
||||
~WeightedLeastSquaresFilterImpl(); |
||||
protected: |
||||
int w,h; |
||||
double sigmaColor,lambda; |
||||
int num_iter; |
||||
double *weights_LUT; |
||||
double *Ahor, *Bhor, *Chor,
|
||||
*Avert, *Bvert, *Cvert; |
||||
double *interD,*interE,*cur_res; |
||||
void init(InputArray guide,double _lambda,double _sigmaColor,int _num_iter); |
||||
void buildCoefMatrices(Mat& guide); |
||||
void horizontalPass(double* cur); |
||||
void verticalPass(double* cur); |
||||
}; |
||||
|
||||
void WeightedLeastSquaresFilterImpl::init(InputArray guide,double _lambda,double _sigmaColor,int _num_iter) |
||||
{ |
||||
//currently support only 3 channel 8bit images as guides
|
||||
CV_Assert( !guide.empty() && _lambda >= 0 && _sigmaColor >= 0 && _num_iter >=1 ); |
||||
CV_Assert( guide.depth() == CV_8U && guide.channels() == 3 ); |
||||
sigmaColor = _sigmaColor; |
||||
lambda = _lambda; |
||||
num_iter = _num_iter; |
||||
int num_levels = 3*256*256; |
||||
weights_LUT = new double[num_levels]; |
||||
for(int i=0;i<num_levels;i++) |
||||
weights_LUT[i] = exp(-sqrt((double)i)/sigmaColor); |
||||
w = guide.cols(); |
||||
h = guide.rows(); |
||||
int sz = w*h; |
||||
Ahor = new double[sz];Bhor = new double[sz];Chor = new double[sz]; |
||||
Avert = new double[sz];Bvert = new double[sz];Cvert = new double[sz]; |
||||
interD = new double[sz];interE = new double[sz];cur_res = new double[sz]; |
||||
Mat guideMat = guide.getMat(); |
||||
buildCoefMatrices(guideMat); |
||||
} |
||||
|
||||
Ptr<WeightedLeastSquaresFilterImpl> WeightedLeastSquaresFilterImpl::create(InputArray guide, double lambda, double sigma_color, int num_iter) |
||||
{ |
||||
WeightedLeastSquaresFilterImpl *wls = new WeightedLeastSquaresFilterImpl(); |
||||
wls->init(guide,lambda,sigma_color,num_iter); |
||||
return Ptr<WeightedLeastSquaresFilterImpl>(wls); |
||||
} |
||||
|
||||
WeightedLeastSquaresFilter::~WeightedLeastSquaresFilter(){} |
||||
WeightedLeastSquaresFilterImpl::~WeightedLeastSquaresFilterImpl() |
||||
{ |
||||
delete[] weights_LUT; |
||||
delete[] Ahor; delete[] Bhor; delete[] Chor; |
||||
delete[] Avert; delete[] Bvert; delete[] Cvert; |
||||
delete[] interD;delete[] interE;delete[] cur_res; |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::buildCoefMatrices(Mat& guide) |
||||
{ |
||||
double hor_weight; |
||||
const unsigned char *row,*row_prev,*row_next; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
//compute horizontal coefs:
|
||||
row = guide.ptr(i); |
||||
Ahor[i*w] = 0; |
||||
hor_weight = weights_LUT[ (row[0]-row[3])*(row[0]-row[3])+ |
||||
(row[1]-row[4])*(row[1]-row[4])+ |
||||
(row[2]-row[5])*(row[2]-row[5]) ]; |
||||
Chor[i*w] = -lambda*hor_weight; |
||||
Bhor[i*w] = 1 - Ahor[i*w] - Chor[i*w]; |
||||
row+=3; |
||||
for(int j=1;j<w-1;j++) |
||||
{ |
||||
Ahor[i*w+j] = -lambda*hor_weight; |
||||
hor_weight = weights_LUT[ (row[0]-row[3])*(row[0]-row[3])+ |
||||
(row[1]-row[4])*(row[1]-row[4])+ |
||||
(row[2]-row[5])*(row[2]-row[5]) ]; |
||||
Chor[i*w+j] = -lambda*hor_weight; |
||||
Bhor[i*w+j] = 1 - Ahor[i*w+j] - Chor[i*w+j]; |
||||
row+=3; |
||||
} |
||||
Ahor[i*w+w-1] = -lambda*hor_weight; |
||||
Chor[i*w+w-1] = 0; |
||||
Bhor[i*w+w-1] = 1 - Ahor[i*w+w-1] - Chor[i*w+w-1]; |
||||
|
||||
//compute vertical coefs:
|
||||
row = guide.ptr(i); |
||||
if(i==0) |
||||
{ |
||||
row_next = guide.ptr(i+1); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
Avert[i*w+j] = 0; |
||||
Cvert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_next[0])*(row[0]-row_next[0])+ |
||||
(row[1]-row_next[1])*(row[1]-row_next[1])+ |
||||
(row[2]-row_next[2])*(row[2]-row_next[2]) ]; |
||||
Bvert[i*w+j] = 1 - Avert[i*w+j] - Cvert[i*w+j]; |
||||
row+=3; |
||||
row_next+=3; |
||||
} |
||||
} |
||||
else if(i==h-1) |
||||
{ |
||||
row_prev = guide.ptr(i-1); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
Avert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_prev[0])*(row[0]-row_prev[0])+ |
||||
(row[1]-row_prev[1])*(row[1]-row_prev[1])+ |
||||
(row[2]-row_prev[2])*(row[2]-row_prev[2]) ]; |
||||
Cvert[i*w+j] = 0; |
||||
Bvert[i*w+j] = 1 - Avert[i*w+j] - Cvert[i*w+j]; |
||||
row+=3; |
||||
row_prev+=3; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
row_prev = guide.ptr(i-1); |
||||
row_next = guide.ptr(i+1); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
Avert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_prev[0])*(row[0]-row_prev[0])+ |
||||
(row[1]-row_prev[1])*(row[1]-row_prev[1])+ |
||||
(row[2]-row_prev[2])*(row[2]-row_prev[2]) ]; |
||||
Cvert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_next[0])*(row[0]-row_next[0])+ |
||||
(row[1]-row_next[1])*(row[1]-row_next[1])+ |
||||
(row[2]-row_next[2])*(row[2]-row_next[2]) ]; |
||||
Bvert[i*w+j] = 1 - Avert[i*w+j] - Cvert[i*w+j]; |
||||
row+=3; |
||||
row_prev+=3; |
||||
row_next+=3; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::filter(InputArray src, OutputArray dst) |
||||
{ |
||||
//temporarily support only one-channel CV_16S src type (for disparity map filtering)
|
||||
CV_Assert(!src.empty() && (src.depth() == CV_16S) && src.channels()==1); |
||||
if (src.rows() != h || src.cols() != w) |
||||
{ |
||||
CV_Error(Error::StsBadSize, "Size of filtering image must be equal to size of guide image"); |
||||
return; |
||||
} |
||||
|
||||
Mat srcMat = src.getMat();
|
||||
Mat& dstMat = dst.getMatRef(); |
||||
short* row; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
row = (short*)srcMat.ptr(i); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
cur_res[i*w+j] = (double)(*row); |
||||
row++; |
||||
} |
||||
} |
||||
|
||||
for(int n=0;n<num_iter;n++) |
||||
{ |
||||
horizontalPass(cur_res); |
||||
verticalPass(cur_res); |
||||
} |
||||
|
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
row = (short*)dstMat.ptr(i); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
*row = saturate_cast<short>(cur_res[i*w+j]); |
||||
row++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::horizontalPass(double* cur) |
||||
{ |
||||
double denom; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
//forward pass:
|
||||
interD[i*w] = Chor[i*w]/Bhor[i*w]; |
||||
interE[i*w] = cur[i*w] /Bhor[i*w]; |
||||
for(int j=1;j<w;j++) |
||||
{ |
||||
denom = Bhor[i*w+j]-interD[i*w+j-1]*Ahor[i*w+j]; |
||||
interD[i*w+j] = Chor[i*w+j]/denom; |
||||
interE[i*w+j] = (cur[i*w+j]-interE[i*w+j-1]*Ahor[i*w+j])/denom; |
||||
} |
||||
|
||||
//backward pass:
|
||||
cur[i*w+w-1] = interE[i*w+w-1]; |
||||
for(int j=w-2;j>=0;j--) |
||||
cur[i*w+j] = interE[i*w+j]-interD[i*w+j]*cur[i*w+j+1]; |
||||
} |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::verticalPass(double* cur) |
||||
{ |
||||
double denom; |
||||
//forward pass:
|
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
interD[j] = Cvert[j]/Bvert[j]; |
||||
interE[j] = cur[j]/Bvert[j]; |
||||
} |
||||
for(int i=1;i<h;i++) |
||||
{ |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
denom = Bvert[i*w+j]-interD[(i-1)*w+j]*Avert[i*w+j]; |
||||
interD[i*w+j] = Cvert[i*w+j]/denom; |
||||
interE[i*w+j] = (cur[i*w+j]-interE[(i-1)*w+j]*Avert[i*w+j])/denom; |
||||
} |
||||
} |
||||
//backward pass:
|
||||
for(int j=0;j<w;j++) |
||||
cur[(h-1)*w+j] = interE[(h-1)*w+j]; |
||||
for(int i=h-2;i>=0;i--) |
||||
for(int j=w-1;j>=0;j--) |
||||
cur[i*w+j] = interE[i*w+j]-interD[i*w+j]*cur[(i+1)*w+j]; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<WeightedLeastSquaresFilter> createWeightedLeastSquaresFilter(InputArray guide, double lambda, double sigma_color, int num_iter) |
||||
{ |
||||
return Ptr<WeightedLeastSquaresFilter>(WeightedLeastSquaresFilterImpl::create(guide, lambda, sigma_color, num_iter)); |
||||
} |
||||
|
||||
CV_EXPORTS_W |
||||
void weightedLeastSquaresFilter(InputArray guide, InputArray src, OutputArray dst, double lambda, double sigma_color, int num_iter) |
||||
{ |
||||
Ptr<WeightedLeastSquaresFilter> wls = createWeightedLeastSquaresFilter(guide, lambda, sigma_color, num_iter); |
||||
wls->filter(src, dst); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,154 @@ |
||||
/*
|
||||
* By downloading, copying, installing or using the software you agree to this license. |
||||
* If you do not agree to this license, do not download, install, |
||||
* copy or use the software. |
||||
* |
||||
* |
||||
* License Agreement |
||||
* For Open Source Computer Vision Library |
||||
* (3 - clause BSD License) |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
* |
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
* |
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* This software is provided by the copyright holders and contributors "as is" and |
||||
* any express or implied warranties, including, but not limited to, the implied |
||||
* warranties of merchantability and fitness for a particular purpose are disclaimed. |
||||
* In no event shall copyright holders or contributors be liable for any direct, |
||||
* indirect, incidental, special, exemplary, or consequential damages |
||||
* (including, but not limited to, procurement of substitute goods or services; |
||||
* loss of use, data, or profits; or business interruption) however caused |
||||
* and on any theory of liability, whether in contract, strict liability, |
||||
* or tort(including negligence or otherwise) arising in any way out of |
||||
* the use of this software, even if advised of the possibility of such damage. |
||||
*/ |
||||
|
||||
#include "test_precomp.hpp" |
||||
#include "opencv2/ximgproc/disparity_filter.hpp" |
||||
|
||||
namespace cvtest |
||||
{ |
||||
|
||||
using namespace std; |
||||
using namespace std::tr1; |
||||
using namespace testing; |
||||
using namespace perf; |
||||
using namespace cv; |
||||
using namespace cv::ximgproc; |
||||
|
||||
static string getDataDir() |
||||
{ |
||||
return cvtest::TS::ptr()->get_data_path(); |
||||
} |
||||
|
||||
CV_ENUM(SrcTypes, CV_16S); |
||||
CV_ENUM(GuideTypes, CV_8UC1, CV_8UC3) |
||||
typedef tuple<Size, SrcTypes, GuideTypes, bool, bool> DisparityWLSParams; |
||||
typedef TestWithParam<DisparityWLSParams> DisparityWLSFilterTest; |
||||
|
||||
TEST(DisparityWLSFilterTest, ReferenceAccuracy) |
||||
{ |
||||
string dir = getDataDir() + "cv/disparityfilter"; |
||||
|
||||
Mat left = imread(dir + "/left_view.png",IMREAD_COLOR); |
||||
ASSERT_FALSE(left.empty()); |
||||
Mat left_disp = imread(dir + "/disparity_left_raw.png",IMREAD_GRAYSCALE); |
||||
ASSERT_FALSE(left_disp.empty()); |
||||
left_disp.convertTo(left_disp,CV_16S,16); |
||||
Mat right_disp = imread(dir + "/disparity_right_raw.png",IMREAD_GRAYSCALE); |
||||
ASSERT_FALSE(right_disp.empty()); |
||||
right_disp.convertTo(right_disp,CV_16S,-16); |
||||
|
||||
Mat GT; |
||||
ASSERT_FALSE(readGT(dir + "/GT.png",GT)); |
||||
|
||||
FileStorage ROI_storage( dir + "/ROI.xml", FileStorage::READ ); |
||||
Rect ROI((int)ROI_storage["x"],(int)ROI_storage["y"],(int)ROI_storage["width"],(int)ROI_storage["height"]); |
||||
|
||||
FileStorage reference_res( dir + "/reference_accuracy.xml", FileStorage::READ ); |
||||
double ref_MSE = (double)reference_res["MSE_after"]; |
||||
double ref_BadPercent = (double)reference_res["BadPercent_after"]; |
||||
|
||||
cv::setNumThreads(cv::getNumberOfCPUs()); |
||||
Mat res; |
||||
|
||||
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilter(true); |
||||
wls_filter->setLambda(8000.0); |
||||
wls_filter->setSigmaColor(0.5); |
||||
wls_filter->filter(left_disp,left,res,ROI,right_disp); |
||||
|
||||
double MSE = computeMSE(GT,res,ROI); |
||||
double BadPercent = computeBadPixelPercent(GT,res,ROI); |
||||
double eps = 0.01; |
||||
|
||||
EXPECT_LE(MSE,ref_MSE+eps*ref_MSE); |
||||
EXPECT_LE(BadPercent,ref_BadPercent+eps*ref_BadPercent); |
||||
} |
||||
|
||||
TEST_P(DisparityWLSFilterTest, MultiThreadReproducibility) |
||||
{ |
||||
if (cv::getNumberOfCPUs() == 1) |
||||
return; |
||||
|
||||
double MAX_DIF = 1.0; |
||||
double MAX_MEAN_DIF = 1.0 / 256.0; |
||||
int loopsCount = 2; |
||||
RNG rng(0); |
||||
|
||||
DisparityWLSParams params = GetParam(); |
||||
Size size = get<0>(params); |
||||
int srcType = get<1>(params); |
||||
int guideType = get<2>(params); |
||||
bool use_conf = get<3>(params); |
||||
bool use_downscale = get<4>(params); |
||||
|
||||
Mat left(size, guideType); |
||||
randu(left, 0, 255); |
||||
Mat left_disp(size,srcType); |
||||
int max_disp = (int)(size.width*0.1); |
||||
randu(left_disp, 0, max_disp-1); |
||||
Mat right_disp(size,srcType); |
||||
randu(left_disp, -max_disp+1, 0); |
||||
Rect ROI(max_disp,0,size.width-max_disp,size.height); |
||||
|
||||
if(use_downscale) |
||||
{ |
||||
resize(left_disp,left_disp,Size(),0.5,0.5); |
||||
resize(right_disp,right_disp,Size(),0.5,0.5); |
||||
ROI = Rect(ROI.x/2,ROI.y/2,ROI.width/2,ROI.height/2); |
||||
} |
||||
|
||||
for (int iter = 0; iter <= loopsCount; iter++) |
||||
{ |
||||
double lambda = rng.uniform(100.0, 10000.0); |
||||
double sigma = rng.uniform(1.0, 100.0); |
||||
|
||||
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilter(use_conf); |
||||
wls_filter->setLambda(lambda); |
||||
wls_filter->setSigmaColor(sigma); |
||||
|
||||
cv::setNumThreads(cv::getNumberOfCPUs()); |
||||
Mat resMultiThread; |
||||
wls_filter->filter(left_disp,left,resMultiThread,ROI,right_disp); |
||||
|
||||
cv::setNumThreads(1); |
||||
Mat resSingleThread; |
||||
wls_filter->filter(left_disp,left,resSingleThread,ROI,right_disp); |
||||
|
||||
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF); |
||||
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF*left.total()); |
||||
} |
||||
} |
||||
INSTANTIATE_TEST_CASE_P(FullSet,DisparityWLSFilterTest,Combine(Values(szODD, szQVGA), SrcTypes::all(), GuideTypes::all(),Values(true,false),Values(true,false))); |
||||
} |
@ -0,0 +1,153 @@ |
||||
/*
|
||||
* By downloading, copying, installing or using the software you agree to this license. |
||||
* If you do not agree to this license, do not download, install, |
||||
* copy or use the software. |
||||
* |
||||
* |
||||
* License Agreement |
||||
* For Open Source Computer Vision Library |
||||
* (3 - clause BSD License) |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
* |
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
* |
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* This software is provided by the copyright holders and contributors "as is" and |
||||
* any express or implied warranties, including, but not limited to, the implied |
||||
* warranties of merchantability and fitness for a particular purpose are disclaimed. |
||||
* In no event shall copyright holders or contributors be liable for any direct, |
||||
* indirect, incidental, special, exemplary, or consequential damages |
||||
* (including, but not limited to, procurement of substitute goods or services; |
||||
* loss of use, data, or profits; or business interruption) however caused |
||||
* and on any theory of liability, whether in contract, strict liability, |
||||
* or tort(including negligence or otherwise) arising in any way out of |
||||
* the use of this software, even if advised of the possibility of such damage. |
||||
*/ |
||||
|
||||
#include "test_precomp.hpp" |
||||
|
||||
namespace cvtest |
||||
{ |
||||
|
||||
using namespace std; |
||||
using namespace std::tr1; |
||||
using namespace testing; |
||||
using namespace perf; |
||||
using namespace cv; |
||||
using namespace cv::ximgproc; |
||||
|
||||
static string getDataDir() |
||||
{ |
||||
return cvtest::TS::ptr()->get_data_path(); |
||||
} |
||||
|
||||
CV_ENUM(SrcTypes, CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC2, CV_16SC3, CV_16SC4, CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4); |
||||
CV_ENUM(GuideTypes, CV_8UC1, CV_8UC3) |
||||
typedef tuple<Size, SrcTypes, GuideTypes> FGSParams; |
||||
typedef TestWithParam<FGSParams> FastGlobalSmootherTest; |
||||
|
||||
TEST(FastGlobalSmootherTest, SplatSurfaceAccuracy) |
||||
{ |
||||
RNG rnd(0); |
||||
|
||||
for (int i = 0; i < 10; i++) |
||||
{ |
||||
Size sz(rnd.uniform(512, 1024), rnd.uniform(512, 1024)); |
||||
|
||||
int guideCn = rnd.uniform(1, 2); |
||||
if(guideCn==2) guideCn++; //1 or 3 channels
|
||||
Mat guide(sz, CV_MAKE_TYPE(CV_8U, guideCn)); |
||||
randu(guide, 0, 255); |
||||
|
||||
Scalar surfaceValue; |
||||
int srcCn = rnd.uniform(1, 4); |
||||
rnd.fill(surfaceValue, RNG::UNIFORM, 0, 255); |
||||
Mat src(sz, CV_MAKE_TYPE(CV_16S, srcCn), surfaceValue); |
||||
|
||||
double lambda = rnd.uniform(100, 10000); |
||||
double sigma = rnd.uniform(1.0, 100.0); |
||||
|
||||
Mat res; |
||||
fastGlobalSmootherFilter(guide, src, res, lambda, sigma); |
||||
|
||||
// When filtering a constant image we should get the same image:
|
||||
double normL1 = cvtest::norm(src, res, NORM_L1)/src.total()/src.channels(); |
||||
EXPECT_LE(normL1, 1.0/64); |
||||
} |
||||
} |
||||
|
||||
TEST(FastGlobalSmootherTest, ReferenceAccuracy) |
||||
{ |
||||
string dir = getDataDir() + "cv/edgefilter"; |
||||
|
||||
Mat src = imread(dir + "/kodim23.png"); |
||||
Mat ref = imread(dir + "/fgs/kodim23_lambda=1000_sigma=10.png"); |
||||
|
||||
ASSERT_FALSE(src.empty()); |
||||
ASSERT_FALSE(ref.empty()); |
||||
|
||||
cv::setNumThreads(cv::getNumberOfCPUs()); |
||||
Mat res; |
||||
fastGlobalSmootherFilter(src,src,res,1000.0,10.0); |
||||
|
||||
double totalMaxError = 1.0/64.0*src.total()*src.channels(); |
||||
|
||||
EXPECT_LE(cvtest::norm(res, ref, NORM_L2), totalMaxError); |
||||
EXPECT_LE(cvtest::norm(res, ref, NORM_INF), 1); |
||||
} |
||||
|
||||
TEST_P(FastGlobalSmootherTest, MultiThreadReproducibility) |
||||
{ |
||||
if (cv::getNumberOfCPUs() == 1) |
||||
return; |
||||
|
||||
double MAX_DIF = 1.0; |
||||
double MAX_MEAN_DIF = 1.0 / 64.0; |
||||
int loopsCount = 2; |
||||
RNG rng(0); |
||||
|
||||
FGSParams params = GetParam(); |
||||
Size size = get<0>(params); |
||||
int srcType = get<1>(params); |
||||
int guideType = get<2>(params); |
||||
|
||||
Mat guide(size, guideType); |
||||
randu(guide, 0, 255); |
||||
Mat src(size,srcType); |
||||
if(src.depth()==CV_8U) |
||||
randu(src, 0, 255); |
||||
else if(src.depth()==CV_16S) |
||||
randu(src, -32767, 32767); |
||||
else |
||||
randu(src, -100000.0f, 100000.0f); |
||||
|
||||
for (int iter = 0; iter <= loopsCount; iter++) |
||||
{ |
||||
double lambda = rng.uniform(100.0, 10000.0); |
||||
double sigma = rng.uniform(1.0, 100.0); |
||||
|
||||
cv::setNumThreads(cv::getNumberOfCPUs()); |
||||
Mat resMultiThread; |
||||
fastGlobalSmootherFilter(guide, src, resMultiThread, lambda, sigma); |
||||
|
||||
cv::setNumThreads(1); |
||||
Mat resSingleThread; |
||||
fastGlobalSmootherFilter(guide, src, resSingleThread, lambda, sigma); |
||||
|
||||
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF); |
||||
EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF*src.total()*src.channels()); |
||||
} |
||||
} |
||||
INSTANTIATE_TEST_CASE_P(FullSet, FastGlobalSmootherTest,Combine(Values(szODD, szQVGA), SrcTypes::all(), GuideTypes::all())); |
||||
|
||||
} |
After Width: | Height: | Size: 182 KiB |
@ -0,0 +1,7 @@ |
||||
<?xml version="1.0"?> |
||||
<opencv_storage> |
||||
<x>166</x> |
||||
<y>7</y> |
||||
<width>851</width> |
||||
<height>422</height> |
||||
</opencv_storage> |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 283 KiB |
@ -0,0 +1,7 @@ |
||||
<?xml version="1.0"?> |
||||
<opencv_storage> |
||||
<MSE_before>5043.6495</MSE_before> |
||||
<MSE_after>128.3773</MSE_after> |
||||
<BadPercent_before>48.5417</BadPercent_before> |
||||
<BadPercent_after>45.8749</BadPercent_after> |
||||
</opencv_storage> |
After Width: | Height: | Size: 287 KiB |
Loading…
Reference in new issue