You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
7.7 KiB
222 lines
7.7 KiB
#include <algorithm> |
|
#include <typeinfo> |
|
#include <cmath> |
|
#define WEIGHTED |
|
|
|
namespace cv{ |
|
|
|
//!particle filtering class |
|
class PFSolver : public MinProblemSolver{ |
|
public: |
|
class Function : public MinProblemSolver::Function |
|
{ |
|
public: |
|
//!if parameters have no sense due to some reason (e.g. lie outside of function domain), this function "corrects" them, |
|
//!that is brings to the function domain |
|
virtual void correctParams(double* /*optParams*/)const{} |
|
//!is used when there is a dependence on the number of iterations done in calc(), note that levels are counted starting from 1 |
|
virtual void setLevel(int /*level*/, int /*levelsNum*/){} |
|
}; |
|
PFSolver(); |
|
void getOptParam(OutputArray params)const; |
|
int iteration(); |
|
double minimize(InputOutputArray x) CV_OVERRIDE; |
|
|
|
void setParticlesNum(int num); |
|
int getParticlesNum(); |
|
void setAlpha(double AlphaM); |
|
double getAlpha(); |
|
void getParamsSTD(OutputArray std)const; |
|
void setParamsSTD(InputArray std); |
|
|
|
Ptr<MinProblemSolver::Function> getFunction() const CV_OVERRIDE; |
|
void setFunction(const Ptr<MinProblemSolver::Function>& f) CV_OVERRIDE; |
|
TermCriteria getTermCriteria() const CV_OVERRIDE; |
|
void setTermCriteria(const TermCriteria& termcrit) CV_OVERRIDE; |
|
private: |
|
Mat_<double> _std,_particles,_logweight; |
|
Ptr<MinProblemSolver::Function> _Function; |
|
PFSolver::Function* _real_function; |
|
TermCriteria _termcrit; |
|
int _maxItNum,_iter,_particlesNum; |
|
double _alpha; |
|
inline void normalize(Mat_<double>& row); |
|
RNG rng; |
|
}; |
|
|
|
CV_EXPORTS_W Ptr<PFSolver> createPFSolver(const Ptr<MinProblemSolver::Function>& f=Ptr<MinProblemSolver::Function>(),InputArray std=Mat(), |
|
TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER,5,0.0),int particlesNum=100,double alpha=0.6); |
|
|
|
PFSolver::PFSolver(){ |
|
_Function=Ptr<MinProblemSolver::Function>(); |
|
_real_function=NULL; |
|
_std=Mat_<double>(); |
|
rng=RNG(getTickCount()); |
|
} |
|
void PFSolver::getOptParam(OutputArray params)const{ |
|
params.create(1,_std.rows,CV_64FC1); |
|
Mat mat(1,_std.rows,CV_64FC1); |
|
#ifdef WEIGHTED |
|
mat.setTo(0.0); |
|
for(int i=0;i<_particles.rows;i++){ |
|
mat+=_particles.row(i)/exp(-_logweight(0,i)); |
|
} |
|
_real_function->correctParams((double*)mat.data); |
|
mat.copyTo(params); |
|
#else |
|
params.create(1,_std.rows,CV_64FC1); |
|
Mat optimus=_particles.row(std::max_element(_logweight.begin(),_logweight.end())-_logweight.begin()); |
|
_real_function->correctParams(optimus.data); |
|
optimus.copyTo(params); |
|
#endif |
|
} |
|
int PFSolver::iteration(){ |
|
if(_iter>=_maxItNum){ |
|
return _maxItNum+1; |
|
} |
|
|
|
_real_function->setLevel(_iter+1,_maxItNum); |
|
|
|
//perturb |
|
for(int j=0;j<_particles.cols;j++){ |
|
double sigma=_std(0,j); |
|
for(int i=0;i<_particles.rows;i++){ |
|
_particles(i,j)+=rng.gaussian(sigma); |
|
} |
|
} |
|
|
|
//measure |
|
for(int i=0;i<_particles.rows;i++){ |
|
_real_function->correctParams((double*)_particles.row(i).data); |
|
_logweight(0,i)=-(_real_function->calc((double*)_particles.row(i).data)); |
|
} |
|
//normalize |
|
normalize(_logweight); |
|
//replicate |
|
Mat_<double> new_particles(_particlesNum,_std.cols); |
|
int num_particles=0; |
|
for(int i=0;i<_particles.rows;i++){ |
|
int num_replicons=cvFloor(new_particles.rows/exp(-_logweight(0,i))); |
|
for(int j=0;j<num_replicons;j++,num_particles++){ |
|
_particles.row(i).copyTo(new_particles.row(num_particles)); |
|
} |
|
} |
|
//Mat_<double> maxrow=_particles.row(std::max_element(_logweight.begin(),_logweight.end())-_logweight.begin()); |
|
double max_element; |
|
minMaxLoc(_logweight, 0, &max_element); |
|
Mat_<double> maxrow=_particles.row((int)max_element); |
|
for(;num_particles<new_particles.rows;num_particles++){ |
|
maxrow.copyTo(new_particles.row(num_particles)); |
|
} |
|
|
|
if(_particles.rows!=new_particles.rows){ |
|
_particles=new_particles; |
|
}else{ |
|
new_particles.copyTo(_particles); |
|
} |
|
_std=_std*_alpha; |
|
_iter++; |
|
return _iter; |
|
} |
|
double PFSolver::minimize(InputOutputArray x){ |
|
CV_Assert(_Function.empty()==false); |
|
CV_Assert(_std.rows==1 && _std.cols>0); |
|
Mat mat_x=x.getMat(); |
|
CV_Assert(mat_x.type()==CV_64FC1 && MIN(mat_x.rows,mat_x.cols)==1 && MAX(mat_x.rows,mat_x.cols)==_std.cols); |
|
|
|
_iter=0; |
|
_particles=Mat_<double>(_particlesNum,_std.cols); |
|
if(mat_x.rows>1){ |
|
mat_x=mat_x.t(); |
|
} |
|
for(int i=0;i<_particles.rows;i++){ |
|
mat_x.copyTo(_particles.row(i)); |
|
} |
|
|
|
_logweight.create(1,_particles.rows); |
|
_logweight.setTo(-log((double)_particles.rows)); |
|
return 0.0; |
|
} |
|
|
|
void PFSolver::setParticlesNum(int num){ |
|
CV_Assert(num>0); |
|
_particlesNum=num; |
|
} |
|
int PFSolver::getParticlesNum(){ |
|
return _particlesNum; |
|
} |
|
void PFSolver::setAlpha(double AlphaM){ |
|
CV_Assert(0<AlphaM && AlphaM<=1); |
|
_alpha=AlphaM; |
|
} |
|
double PFSolver::getAlpha(){ |
|
return _alpha; |
|
} |
|
Ptr<MinProblemSolver::Function> PFSolver::getFunction() const{ |
|
return _Function; |
|
} |
|
void PFSolver::setFunction(const Ptr<MinProblemSolver::Function>& f){ |
|
CV_Assert(f.empty()==false); |
|
|
|
Ptr<MinProblemSolver::Function> non_const_f(f); |
|
MinProblemSolver::Function* f_ptr=static_cast<MinProblemSolver::Function*>(non_const_f); |
|
|
|
PFSolver::Function *pff=dynamic_cast<PFSolver::Function*>(f_ptr); |
|
CV_Assert(pff!=NULL); |
|
_Function=f; |
|
_real_function=pff; |
|
} |
|
TermCriteria PFSolver::getTermCriteria() const{ |
|
return TermCriteria(TermCriteria::MAX_ITER,_maxItNum,0.0); |
|
} |
|
void PFSolver::setTermCriteria(const TermCriteria& termcrit){ |
|
CV_Assert(termcrit.type==TermCriteria::MAX_ITER && termcrit.maxCount>0); |
|
_maxItNum=termcrit.maxCount; |
|
} |
|
void PFSolver::getParamsSTD(OutputArray std)const{ |
|
std.create(1,_std.cols,CV_64FC1); |
|
_std.copyTo(std); |
|
} |
|
void PFSolver::setParamsSTD(InputArray std){ |
|
Mat m=std.getMat(); |
|
CV_Assert(MIN(m.cols,m.rows)==1 && m.type()==CV_64FC1); |
|
int ndim=MAX(m.cols,m.rows); |
|
if(ndim!=_std.cols){ |
|
_std=Mat_<double>(1,ndim); |
|
} |
|
if(m.rows==1){ |
|
m.copyTo(_std); |
|
}else{ |
|
Mat std_t=Mat_<double>(ndim,1,(double*)_std.data); |
|
m.copyTo(std_t); |
|
} |
|
} |
|
|
|
Ptr<PFSolver> createPFSolver(const Ptr<MinProblemSolver::Function>& f,InputArray std,TermCriteria termcrit,int particlesNum,double alpha){ |
|
Ptr<PFSolver> ptr(new PFSolver()); |
|
|
|
if(f.empty()==false){ |
|
ptr->setFunction(f); |
|
} |
|
Mat mystd=std.getMat(); |
|
if(mystd.cols!=0 || mystd.rows!=0){ |
|
ptr->setParamsSTD(std); |
|
} |
|
ptr->setTermCriteria(termcrit); |
|
ptr->setParticlesNum(particlesNum); |
|
ptr->setAlpha(alpha); |
|
return ptr; |
|
} |
|
void PFSolver::normalize(Mat_<double>& row){ |
|
double logsum=0.0; |
|
//double max=*(std::max_element(row.begin(),row.end())); |
|
double max; |
|
minMaxLoc(row, 0, &max); |
|
row-=max; |
|
for(int i=0;i<row.cols;i++){ |
|
logsum+=exp(row(0,i)); |
|
} |
|
logsum=log(logsum); |
|
row-=logsum; |
|
} |
|
}
|
|
|