Created
October 4, 2016 09:32
-
-
Save alasin/5b31779ce763ced3b1f55882828102ba to your computer and use it in GitHub Desktop.
Code for WLS filter for OpenCV version <3.1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define EPS 1e-43f | |
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 FastGlobalSmootherFilter | |
{ | |
public: | |
/** @brief Apply smoothing operation to the source image. | |
@param src source image for filtering with unsigned 8-bit or signed 16-bit or floating-point 32-bit depth and up to 4 channels. | |
@param dst destination image. | |
*/ | |
virtual void filter(InputArray src, OutputArray dst) = 0; | |
}; | |
Ptr<FastGlobalSmootherFilter> createFastGlobalSmootherFilter(InputArray guide, double lambda, double sigma_color, double lambda_attenuation=0.25, int num_iter=3); | |
void fastGlobalSmootherFilter(InputArray guide, InputArray src, OutputArray dst, double lambda, double sigma_color, double lambda_attenuation=0.25, int num_iter=3); | |
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)); | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////// | |
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)); | |
} | |
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); | |
} | |
class DisparityWLSFilter | |
{ | |
protected: | |
int left_offset, right_offset, top_offset, bottom_offset; | |
Rect valid_disp_ROI; | |
Rect right_view_valid_disp_ROI; | |
int min_disp; | |
bool use_confidence; | |
Mat confidence_map; | |
double lambda,sigma_color; | |
int LRC_thresh,depth_discontinuity_radius; | |
float depth_discontinuity_roll_off_factor; | |
float resize_factor; | |
int num_stripes; | |
void init(double _lambda, double _sigma_color, bool _use_confidence, int l_offs, int r_offs, int t_offs, int b_offs, int _min_disp); | |
void computeDepthDiscontinuityMaps(Mat& left_disp, Mat& right_disp, Mat& left_dst, Mat& right_dst); | |
void computeConfidenceMap(InputArray left_disp, InputArray right_disp); | |
protected: | |
struct ComputeDiscontinuityAwareLRC_ParBody : public ParallelLoopBody | |
{ | |
DisparityWLSFilter* wls; | |
Mat *left_disp, *right_disp; | |
Mat *left_disc, *right_disc, *dst; | |
Rect left_ROI, right_ROI; | |
int nstripes, stripe_sz; | |
ComputeDiscontinuityAwareLRC_ParBody(DisparityWLSFilter& _wls, Mat& _left_disp, Mat& _right_disp, Mat& _left_disc, Mat& _right_disc, Mat& _dst, Rect _left_ROI, Rect _right_ROI, int _nstripes); | |
void operator () (const Range& range) const; | |
}; | |
struct ComputeDepthDisc_ParBody : public ParallelLoopBody | |
{ | |
DisparityWLSFilter* wls; | |
Mat *disp,*disp_squares,*dst; | |
int nstripes, stripe_sz; | |
ComputeDepthDisc_ParBody(DisparityWLSFilter& _wls, Mat& _disp, Mat& _disp_squares, Mat& _dst, int _nstripes); | |
void operator () (const Range& range) const; | |
}; | |
typedef void (DisparityWLSFilter::*MatOp)(Mat& src, Mat& dst); | |
struct ParallelMatOp_ParBody : public ParallelLoopBody | |
{ | |
DisparityWLSFilter* wls; | |
vector<MatOp> ops; | |
vector<Mat*> src; | |
vector<Mat*> dst; | |
ParallelMatOp_ParBody(DisparityWLSFilter& _wls, vector<MatOp> _ops, vector<Mat*>& _src, vector<Mat*>& _dst); | |
void operator () (const Range& range) const; | |
}; | |
void boxFilterOp(Mat& src,Mat& dst) | |
{ | |
int rad = depth_discontinuity_radius; | |
boxFilter(src,dst,CV_32F,Size(2*rad+1,2*rad+1),Point(-1,-1)); | |
} | |
void sqrBoxFilterOp(Mat& src,Mat& dst) | |
{ | |
int rad = depth_discontinuity_radius; | |
sqrBoxFilter(src,dst,CV_32F,Size(2*rad+1,2*rad+1),Point(-1,-1)); | |
} | |
void copyToOp(Mat& src,Mat& dst) | |
{ | |
src.copyTo(dst); | |
} | |
public: | |
static Ptr<DisparityWLSFilter> create(bool _use_confidence, int l_offs, int r_offs, int t_offs, int b_offs, int min_disp); | |
void filter(InputArray disparity_map_left, InputArray left_view, OutputArray filtered_disparity_map, InputArray disparity_map_right, Rect ROI, InputArray); | |
double getLambda() {return lambda;} | |
void setLambda(double _lambda) {lambda = _lambda;} | |
double getSigmaColor() {return sigma_color;} | |
void setSigmaColor(double _sigma_color) {sigma_color = _sigma_color;} | |
int getLRCthresh() {return LRC_thresh;} | |
void setLRCthresh(int _LRC_thresh) {LRC_thresh = _LRC_thresh;} | |
int getDepthDiscontinuityRadius() {return depth_discontinuity_radius;} | |
void setDepthDiscontinuityRadius(int _disc_radius) {depth_discontinuity_radius = _disc_radius;} | |
Mat getConfidenceMap() {return confidence_map;} | |
Rect getROI() {return valid_disp_ROI;} | |
}; | |
void DisparityWLSFilter::init(double _lambda, double _sigma_color, bool _use_confidence, int l_offs, int r_offs, int t_offs, int b_offs, int _min_disp) | |
{ | |
left_offset = l_offs; right_offset = r_offs; | |
top_offset = t_offs; bottom_offset = b_offs; | |
min_disp = _min_disp; | |
valid_disp_ROI = Rect(); | |
right_view_valid_disp_ROI = Rect(); | |
min_disp=0; | |
lambda = _lambda; | |
sigma_color = _sigma_color; | |
use_confidence = _use_confidence; | |
confidence_map = Mat(); | |
LRC_thresh = 24; | |
depth_discontinuity_radius = 5; | |
depth_discontinuity_roll_off_factor = 0.001f; | |
resize_factor = 1.0; | |
num_stripes = getNumThreads(); | |
} | |
void DisparityWLSFilter::computeDepthDiscontinuityMaps(Mat& left_disp, Mat& right_disp, Mat& left_dst, Mat& right_dst) | |
{ | |
Mat left_disp_ROI (left_disp, valid_disp_ROI); | |
Mat right_disp_ROI(right_disp,right_view_valid_disp_ROI); | |
Mat ldisp,rdisp,ldisp_squared,rdisp_squared; | |
{ | |
vector<Mat*> _src; _src.push_back(&left_disp_ROI);_src.push_back(&right_disp_ROI); | |
_src.push_back(&left_disp_ROI);_src.push_back(&right_disp_ROI); | |
vector<Mat*> _dst; _dst.push_back(&ldisp); _dst.push_back(&rdisp); | |
_dst.push_back(&ldisp_squared);_dst.push_back(&rdisp_squared); | |
vector<MatOp> _ops; _ops.push_back(&DisparityWLSFilter::copyToOp); _ops.push_back(&DisparityWLSFilter::copyToOp); | |
_ops.push_back(&DisparityWLSFilter::copyToOp); _ops.push_back(&DisparityWLSFilter::copyToOp); | |
parallel_for_(Range(0,4),ParallelMatOp_ParBody(*this,_ops,_src,_dst)); | |
} | |
{ | |
vector<Mat*> _src; _src.push_back(&ldisp); _src.push_back(&rdisp); | |
_src.push_back(&ldisp_squared);_src.push_back(&rdisp_squared); | |
vector<Mat*> _dst; _dst.push_back(&ldisp); _dst.push_back(&rdisp); | |
_dst.push_back(&ldisp_squared);_dst.push_back(&rdisp_squared); | |
vector<MatOp> _ops; _ops.push_back(&DisparityWLSFilter::boxFilterOp); _ops.push_back(&DisparityWLSFilter::boxFilterOp); | |
_ops.push_back(&DisparityWLSFilter::sqrBoxFilterOp);_ops.push_back(&DisparityWLSFilter::sqrBoxFilterOp); | |
parallel_for_(Range(0,4),ParallelMatOp_ParBody(*this,_ops,_src,_dst)); | |
} | |
left_dst = Mat::zeros(left_disp.rows,left_disp.cols,CV_32F); | |
right_dst = Mat::zeros(right_disp.rows,right_disp.cols,CV_32F); | |
Mat left_dst_ROI (left_dst,valid_disp_ROI); | |
Mat right_dst_ROI(right_dst,right_view_valid_disp_ROI); | |
parallel_for_(Range(0,num_stripes),ComputeDepthDisc_ParBody(*this,ldisp,ldisp_squared,left_dst_ROI ,num_stripes)); | |
parallel_for_(Range(0,num_stripes),ComputeDepthDisc_ParBody(*this,rdisp,rdisp_squared,right_dst_ROI,num_stripes)); | |
} | |
void DisparityWLSFilter::computeConfidenceMap(InputArray left_disp, InputArray right_disp) | |
{ | |
Mat ldisp = left_disp.getMat(); | |
Mat rdisp = right_disp.getMat(); | |
Mat depth_discontinuity_map_left,depth_discontinuity_map_right; | |
right_view_valid_disp_ROI = Rect(ldisp.cols-(valid_disp_ROI.x+valid_disp_ROI.width),valid_disp_ROI.y, | |
valid_disp_ROI.width,valid_disp_ROI.height); | |
computeDepthDiscontinuityMaps(ldisp,rdisp,depth_discontinuity_map_left,depth_discontinuity_map_right); | |
confidence_map = depth_discontinuity_map_left; | |
parallel_for_(Range(0,num_stripes),ComputeDiscontinuityAwareLRC_ParBody(*this,ldisp,rdisp, depth_discontinuity_map_left,depth_discontinuity_map_right,confidence_map,valid_disp_ROI,right_view_valid_disp_ROI,num_stripes)); | |
confidence_map = 255.0f*confidence_map; | |
} | |
Ptr<DisparityWLSFilter> DisparityWLSFilter::create(bool _use_confidence, int l_offs=0, int r_offs=0, int t_offs=0, int b_offs=0, int min_disp=0) | |
{ | |
DisparityWLSFilter *wls = new DisparityWLSFilter(); | |
wls->init(8000.0,1.0,_use_confidence,l_offs, r_offs, t_offs, b_offs, min_disp); | |
return Ptr<DisparityWLSFilter>(wls); | |
} | |
void DisparityWLSFilter::filter(InputArray disparity_map_left, InputArray left_view, OutputArray filtered_disparity_map, InputArray disparity_map_right, Rect ROI, InputArray) | |
{ | |
CV_Assert( !disparity_map_left.empty() && (disparity_map_left.depth() == CV_16S) && (disparity_map_left.channels() == 1) ); | |
CV_Assert( !left_view.empty() && (left_view.depth() == CV_8U) && (left_view.channels() == 3 || left_view.channels() == 1) ); | |
Mat disp,src,dst; | |
if(disparity_map_left.size()!=left_view.size()) | |
resize_factor = disparity_map_left.cols()/(float)left_view.cols(); | |
else | |
resize_factor = 1.0; | |
if(ROI.area()!=0) /* user provided a ROI */ | |
valid_disp_ROI = ROI; | |
else | |
valid_disp_ROI = Rect(left_offset,top_offset, | |
disparity_map_left.cols()-left_offset-right_offset, | |
disparity_map_left.rows()-top_offset-bottom_offset); | |
if(!use_confidence) | |
{ | |
Mat disp_full_size = disparity_map_left.getMat(); | |
Mat src_full_size = left_view.getMat(); | |
if(disp_full_size.size!=src_full_size.size) | |
{ | |
float x_ratio = src_full_size.cols/(float)disp_full_size.cols; | |
float y_ratio = src_full_size.rows/(float)disp_full_size.rows; | |
resize(disp_full_size,disp_full_size,src_full_size.size()); | |
disp_full_size = disp_full_size*x_ratio; | |
ROI = Rect((int)(valid_disp_ROI.x*x_ratio), (int)(valid_disp_ROI.y*y_ratio), | |
(int)(valid_disp_ROI.width*x_ratio),(int)(valid_disp_ROI.height*y_ratio)); | |
} | |
else | |
ROI = valid_disp_ROI; | |
disp = Mat(disp_full_size,ROI); | |
src = Mat(src_full_size ,ROI); | |
filtered_disparity_map.create(disp_full_size.size(), disp_full_size.type()); | |
Mat& dst_full_size = filtered_disparity_map.getMatRef(); | |
dst_full_size = Scalar(16*(min_disp-1)); | |
dst = Mat(dst_full_size,ROI); | |
Mat filtered_disp; | |
fastGlobalSmootherFilter(src,disp,filtered_disp,lambda,sigma_color); | |
filtered_disp.copyTo(dst); | |
} | |
else | |
{ | |
CV_Assert( !disparity_map_right.empty() && (disparity_map_right.depth() == CV_16S) && (disparity_map_right.channels() == 1) ); | |
CV_Assert( (disparity_map_left.cols() == disparity_map_right.cols()) ); | |
CV_Assert( (disparity_map_left.rows() == disparity_map_right.rows()) ); | |
computeConfidenceMap(disparity_map_left,disparity_map_right); | |
Mat disp_full_size = disparity_map_left.getMat(); | |
Mat src_full_size = left_view.getMat(); | |
if(disp_full_size.size!=src_full_size.size) | |
{ | |
float x_ratio = src_full_size.cols/(float)disp_full_size.cols; | |
float y_ratio = src_full_size.rows/(float)disp_full_size.rows; | |
resize(disp_full_size,disp_full_size,src_full_size.size()); | |
disp_full_size = disp_full_size*x_ratio; | |
resize(confidence_map,confidence_map,src_full_size.size()); | |
ROI = Rect((int)(valid_disp_ROI.x*x_ratio), (int)(valid_disp_ROI.y*y_ratio), | |
(int)(valid_disp_ROI.width*x_ratio),(int)(valid_disp_ROI.height*y_ratio)); | |
} | |
else | |
ROI = valid_disp_ROI; | |
disp = Mat(disp_full_size,ROI); | |
src = Mat(src_full_size ,ROI); | |
filtered_disparity_map.create(disp_full_size.size(), disp_full_size.type()); | |
Mat& dst_full_size = filtered_disparity_map.getMatRef(); | |
dst_full_size = Scalar(16*(min_disp-1)); | |
dst = Mat(dst_full_size,ROI); | |
Mat conf(confidence_map,ROI); | |
Mat disp_mul_conf; | |
disp.convertTo(disp_mul_conf,CV_32F); | |
disp_mul_conf = conf.mul(disp_mul_conf); | |
Mat conf_filtered; | |
Ptr<FastGlobalSmootherFilter> wls = createFastGlobalSmootherFilter(src,lambda,sigma_color); | |
wls->filter(disp_mul_conf,disp_mul_conf); | |
wls->filter(conf,conf_filtered); | |
disp_mul_conf = disp_mul_conf.mul(1/(conf_filtered+EPS)); | |
disp_mul_conf.convertTo(dst,CV_16S); | |
} | |
} | |
DisparityWLSFilter::ComputeDiscontinuityAwareLRC_ParBody::ComputeDiscontinuityAwareLRC_ParBody(DisparityWLSFilter& _wls, Mat& _left_disp, Mat& _right_disp, Mat& _left_disc, Mat& _right_disc, Mat& _dst, Rect _left_ROI, Rect _right_ROI, int _nstripes): | |
wls(&_wls),left_disp(&_left_disp),right_disp(&_right_disp),left_disc(&_left_disc),right_disc(&_right_disc),dst(&_dst),left_ROI(_left_ROI),right_ROI(_right_ROI),nstripes(_nstripes) | |
{ | |
stripe_sz = (int)ceil(left_disp->rows/(double)nstripes); | |
} | |
void DisparityWLSFilter::ComputeDiscontinuityAwareLRC_ParBody::operator() (const Range& range) const | |
{ | |
short* row_left; | |
float* row_left_conf; | |
short* row_right; | |
float* row_right_conf; | |
float* row_dst; | |
int right_idx; | |
int h = left_disp->rows; | |
int start = std::min(range.start * stripe_sz, h); | |
int end = std::min(range.end * stripe_sz, h); | |
int thresh = (int)(wls->resize_factor*wls->LRC_thresh); | |
for(int i=start;i<end;i++) | |
{ | |
row_left = (short*)left_disp->ptr(i); | |
row_left_conf = (float*)left_disc->ptr(i); | |
row_right = (short*)right_disp->ptr(i); | |
row_right_conf = (float*)right_disc->ptr(i); | |
row_dst = (float*)dst->ptr(i); | |
int j_start = left_ROI.x; | |
int j_end = left_ROI.x+left_ROI.width; | |
int right_end = right_ROI.x+right_ROI.width; | |
for(int j=j_start;j<j_end;j++) | |
{ | |
right_idx = j-(row_left[j]>>4); | |
if( right_idx>=right_ROI.x && right_idx<right_end) | |
{ | |
if(abs(row_left[j] + row_right[right_idx])< thresh) | |
row_dst[j] = min(row_left_conf[j],row_right_conf[right_idx]); | |
else | |
row_dst[j] = 0.0f; | |
} | |
} | |
} | |
} | |
DisparityWLSFilter::ComputeDepthDisc_ParBody::ComputeDepthDisc_ParBody(DisparityWLSFilter& _wls, Mat& _disp, Mat& _disp_squares, Mat& _dst, int _nstripes): | |
wls(&_wls),disp(&_disp),disp_squares(&_disp_squares),dst(&_dst),nstripes(_nstripes) | |
{ | |
stripe_sz = (int)ceil(disp->rows/(double)nstripes); | |
} | |
void DisparityWLSFilter::ComputeDepthDisc_ParBody::operator() (const Range& range) const | |
{ | |
float* row_disp; | |
float* row_disp_squares; | |
float* row_dst; | |
float variance; | |
int h = disp->rows; | |
int w = disp->cols; | |
int start = std::min(range.start * stripe_sz, h); | |
int end = std::min(range.end * stripe_sz, h); | |
float roll_off = wls->depth_discontinuity_roll_off_factor/(wls->resize_factor*wls->resize_factor); | |
for(int i=start;i<end;i++) | |
{ | |
row_disp = (float*)disp->ptr(i); | |
row_disp_squares = (float*)disp_squares->ptr(i); | |
row_dst = (float*)dst->ptr(i); | |
for(int j=0;j<w;j++) | |
{ | |
variance = row_disp_squares[j] - (row_disp[j])*(row_disp[j]); | |
row_dst[j] = max(1.0f - roll_off*variance,0.0f); | |
} | |
} | |
} | |
DisparityWLSFilter::ParallelMatOp_ParBody::ParallelMatOp_ParBody(DisparityWLSFilter& _wls, vector<MatOp> _ops, vector<Mat*>& _src, vector<Mat*>& _dst): | |
wls(&_wls),ops(_ops),src(_src),dst(_dst) | |
{} | |
void DisparityWLSFilter::ParallelMatOp_ParBody::operator() (const Range& range) const | |
{ | |
for(int i=range.start;i<range.end;i++) | |
(wls->*ops[i])(*src[i],*dst[i]); | |
} | |
Ptr<DisparityWLSFilter> createDisparityWLSFilter(Ptr<StereoMatcher> matcher_left) | |
{ | |
Ptr<DisparityWLSFilter> wls; | |
matcher_left->setDisp12MaxDiff(1000000); | |
matcher_left->setSpeckleWindowSize(0); | |
int min_disp = matcher_left->getMinDisparity(); | |
int num_disp = matcher_left->getNumDisparities(); | |
int wsize = matcher_left->getBlockSize(); | |
int wsize2 = wsize/2; | |
if(Ptr<StereoBM> bm = matcher_left.dynamicCast<StereoBM>()) | |
{ | |
bm->setTextureThreshold(0); | |
bm->setUniquenessRatio(0); | |
wls = DisparityWLSFilter::create(true,max(0,min_disp+num_disp)+wsize2,max(0,-min_disp)+wsize2,wsize2,wsize2,min_disp); | |
wls->setDepthDiscontinuityRadius((int)ceil(0.33*wsize)); | |
} | |
else if(Ptr<StereoSGBM> sgbm = matcher_left.dynamicCast<StereoSGBM>()) | |
{ | |
sgbm->setUniquenessRatio(0); | |
wls = DisparityWLSFilter::create(true,max(0,min_disp+num_disp),max(0,-min_disp),0,0,min_disp); | |
wls->setDepthDiscontinuityRadius((int)ceil(0.5*wsize)); | |
} | |
else | |
CV_Error(Error::StsBadArg, "DisparityWLSFilter natively supports only StereoBM and StereoSGBM"); | |
return wls; | |
} | |
Ptr<StereoMatcher> createRightMatcher(Ptr<StereoMatcher> matcher_left) | |
{ | |
int min_disp = matcher_left->getMinDisparity(); | |
int num_disp = matcher_left->getNumDisparities(); | |
int wsize = matcher_left->getBlockSize(); | |
if(Ptr<StereoBM> bm = matcher_left.dynamicCast<StereoBM>()) | |
{ | |
Ptr<StereoBM> right_bm = StereoBM::create(num_disp,wsize); | |
right_bm->setMinDisparity(-(min_disp+num_disp)+1); | |
right_bm->setTextureThreshold(0); | |
right_bm->setUniquenessRatio(0); | |
right_bm->setDisp12MaxDiff(1000000); | |
right_bm->setSpeckleWindowSize(0); | |
return right_bm; | |
} | |
else if(Ptr<StereoSGBM> sgbm = matcher_left.dynamicCast<StereoSGBM>()) | |
{ | |
Ptr<StereoSGBM> right_sgbm = StereoSGBM::create(-(min_disp+num_disp)+1,num_disp,wsize); | |
right_sgbm->setUniquenessRatio(0); | |
right_sgbm->setP1(sgbm->getP1()); | |
right_sgbm->setP2(sgbm->getP2()); | |
right_sgbm->setMode(sgbm->getMode()); | |
right_sgbm->setPreFilterCap(sgbm->getPreFilterCap()); | |
right_sgbm->setDisp12MaxDiff(1000000); | |
right_sgbm->setSpeckleWindowSize(0); | |
return right_sgbm; | |
} | |
else | |
{ | |
CV_Error(Error::StsBadArg, "createRightMatcher supports only StereoBM and StereoSGBM"); | |
return Ptr<StereoMatcher>(); | |
} | |
} | |
Ptr<DisparityWLSFilter> createDisparityWLSFilterGeneric(bool use_confidence) | |
{ | |
return Ptr<DisparityWLSFilter>(DisparityWLSFilter::create(use_confidence)); | |
} | |
////////////////////////////////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////// | |
#define UNKNOWN_DISPARITY 16320 | |
int readGT(String src_path,OutputArray dst) | |
{ | |
Mat src = imread(src_path,IMREAD_UNCHANGED); | |
dst.create(src.rows,src.cols,CV_16S); | |
Mat& dstMat = dst.getMatRef(); | |
if(!src.empty() && src.channels()==3 && src.depth()==CV_8U) | |
{ | |
//MPI-Sintel format: | |
for(int i=0;i<src.rows;i++) | |
for(int j=0;j<src.cols;j++) | |
{ | |
Vec3b bgrPixel = src.at<Vec3b>(i, j); | |
dstMat.at<short>(i,j) = 64*bgrPixel.val[2]+bgrPixel.val[1]/4; //16-multiplied disparity | |
} | |
return 0; | |
} | |
else if(!src.empty() && src.channels()==1 && src.depth()==CV_8U) | |
{ | |
//Middlebury format: | |
for(int i=0;i<src.rows;i++) | |
for(int j=0;j<src.cols;j++) | |
{ | |
short src_val = src.at<unsigned char>(i, j); | |
if(src_val==0) | |
dstMat.at<short>(i,j) = UNKNOWN_DISPARITY; | |
else | |
dstMat.at<short>(i,j) = 16*src_val; //16-multiplied disparity | |
} | |
return 0; | |
} | |
else | |
return 1; | |
} | |
double computeMSE(InputArray GT, InputArray src, Rect ROI) | |
{ | |
CV_Assert( !GT.empty() && (GT.depth() == CV_16S) && (GT.channels() == 1) ); | |
CV_Assert( !src.empty() && (src.depth() == CV_16S) && (src.channels() == 1) ); | |
CV_Assert( src.rows() == GT.rows() && src.cols() == GT.cols() ); | |
double res = 0; | |
Mat GT_ROI (GT.getMat(), ROI); | |
Mat src_ROI(src.getMat(),ROI); | |
int cnt=0; | |
for(int i=0;i<src_ROI.rows;i++) | |
for(int j=0;j<src_ROI.cols;j++) | |
{ | |
if(GT_ROI.at<short>(i,j)!=UNKNOWN_DISPARITY) | |
{ | |
res += (GT_ROI.at<short>(i,j) - src_ROI.at<short>(i,j))*(GT_ROI.at<short>(i,j) - src_ROI.at<short>(i,j)); | |
cnt++; | |
} | |
} | |
res /= cnt*256; | |
return res; | |
} | |
double computeBadPixelPercent(InputArray GT, InputArray src, Rect ROI, int thresh) | |
{ | |
CV_Assert( !GT.empty() && (GT.depth() == CV_16S) && (GT.channels() == 1) ); | |
CV_Assert( !src.empty() && (src.depth() == CV_16S) && (src.channels() == 1) ); | |
CV_Assert( src.rows() == GT.rows() && src.cols() == GT.cols() ); | |
int bad_pixel_num = 0; | |
Mat GT_ROI (GT.getMat(), ROI); | |
Mat src_ROI(src.getMat(),ROI); | |
int cnt=0; | |
for(int i=0;i<src_ROI.rows;i++) | |
for(int j=0;j<src_ROI.cols;j++) | |
{ | |
if(GT_ROI.at<short>(i,j)!=UNKNOWN_DISPARITY) | |
{ | |
if( abs(GT_ROI.at<short>(i,j) - src_ROI.at<short>(i,j))>=thresh ) | |
bad_pixel_num++; | |
cnt++; | |
} | |
} | |
return (100.0*bad_pixel_num)/cnt; | |
} | |
void getDisparityVis(InputArray src,OutputArray dst,double scale) | |
{ | |
CV_Assert( !src.empty() && (src.depth() == CV_16S) && (src.channels() == 1) ); | |
Mat srcMat = src.getMat(); | |
dst.create(srcMat.rows,srcMat.cols,CV_8UC1); | |
Mat& dstMat = dst.getMatRef(); | |
for(int i=0;i<dstMat.rows;i++) | |
for(int j=0;j<dstMat.cols;j++) | |
{ | |
if(srcMat.at<short>(i,j)==UNKNOWN_DISPARITY) | |
dstMat.at<unsigned char>(i,j) = 0; | |
else | |
dstMat.at<unsigned char>(i,j) = saturate_cast<unsigned char>(scale*srcMat.at<short>(i,j)/16.0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment