PFSolver.hpp 7.72 KB
Newer Older
1
#include "opencv2/core.hpp"
2 3 4 5 6 7 8 9 10
#include "opencv2/core/core_c.h"
#include <algorithm>
#include <typeinfo>
#include <cmath>
#define WEIGHTED

namespace cv{

    //!particle filtering class
11
    class PFSolver : public MinProblemSolver{
12
    public:
13
        class Function : public MinProblemSolver::Function
14 15 16 17 18 19 20 21 22 23 24
        {
        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();
25
        double minimize(InputOutputArray x) CV_OVERRIDE;
26 27 28 29 30 31 32 33

        void setParticlesNum(int num);
        int getParticlesNum();
        void setAlpha(double AlphaM);
        double getAlpha();
        void getParamsSTD(OutputArray std)const;
        void setParamsSTD(InputArray std);

34 35 36 37
        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;
38 39
    private:
        Mat_<double> _std,_particles,_logweight;
40
        Ptr<MinProblemSolver::Function> _Function;
41 42 43 44 45 46 47 48
        PFSolver::Function* _real_function;
        TermCriteria _termcrit;
        int _maxItNum,_iter,_particlesNum;
        double _alpha;
        inline void normalize(Mat_<double>& row);
        RNG rng;
    };

49
    CV_EXPORTS_W Ptr<PFSolver> createPFSolver(const Ptr<MinProblemSolver::Function>& f=Ptr<MinProblemSolver::Function>(),InputArray std=Mat(),
50 51 52
            TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER,5,0.0),int particlesNum=100,double alpha=0.6);

    PFSolver::PFSolver(){
53
        _Function=Ptr<MinProblemSolver::Function>();
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
        _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));
            }
        }
106 107 108
        //Mat_<double> maxrow=_particles.row(std::max_element(_logweight.begin(),_logweight.end())-_logweight.begin());
        double max_element;
        minMaxLoc(_logweight, 0, &max_element);
Ilya Lavrenov's avatar
Ilya Lavrenov committed
109
        Mat_<double> maxrow=_particles.row((int)max_element);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
        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);
Ilya Lavrenov's avatar
Ilya Lavrenov committed
139
        _logweight.setTo(-log((double)_particles.rows));
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        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;
    }
157
    Ptr<MinProblemSolver::Function> PFSolver::getFunction() const{
158 159
        return _Function;
    }
160
    void PFSolver::setFunction(const Ptr<MinProblemSolver::Function>& f){
161 162
        CV_Assert(f.empty()==false);

163 164
        Ptr<MinProblemSolver::Function> non_const_f(f);
        MinProblemSolver::Function* f_ptr=static_cast<MinProblemSolver::Function*>(non_const_f);
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

        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);
        }
    }

197
    Ptr<PFSolver> createPFSolver(const Ptr<MinProblemSolver::Function>& f,InputArray std,TermCriteria termcrit,int particlesNum,double alpha){
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
            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;
214 215 216
        //double max=*(std::max_element(row.begin(),row.end()));
        double max;
        minMaxLoc(row, 0, &max);
217 218 219 220 221 222 223 224
        row-=max;
        for(int i=0;i<row.cols;i++){
            logsum+=exp(row(0,i));
        }
        logsum=log(logsum);
        row-=logsum;
    }
}