This is an automated email from the git hooks/post-receive script. sebastic-guest pushed a commit to branch upstream-master in repository pktools.
commit 629acee6e13df04d491fa2a31a68fd60ca3e2c95 Author: Pieter Kempeneers <kempe...@gmail.com> Date: Mon Oct 13 16:27:48 2014 +0200 filebuffer for ndvi in pkcomposite --- ChangeLog | 1 + src/algorithms/Filter.cc | 46 ++-- src/algorithms/Filter.h | 514 +++++++++++++++++++-------------------- src/algorithms/ImgRegression.cc | 2 +- src/apps/pkcomposite.cc | 8 +- src/apps/pkfilter.cc | 11 +- src/apps/pkkalman.cc | 264 ++++++++++++++++---- src/imageclasses/ImgReaderGdal.h | 27 +- 8 files changed, 514 insertions(+), 359 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7dda69c..3eb5e35 100755 --- a/ChangeLog +++ b/ChangeLog @@ -310,6 +310,7 @@ version 2.5.4 Support multiple input bands when calculating statistics - pkfilter Support filtering and statistics in spectral domain (see ticket #43252) + Support different padding strategies (currently only supported for spectral/temporal filtering) - pkextract bug fix for proportion rule support standard deviation rule (stdev) for polygon features (ticket #43193) diff --git a/src/algorithms/Filter.cc b/src/algorithms/Filter.cc index 82bd26d..4241d41 100644 --- a/src/algorithms/Filter.cc +++ b/src/algorithms/Filter.cc @@ -25,11 +25,13 @@ along with pktools. If not, see <http://www.gnu.org/licenses/>. using namespace std; filter::Filter::Filter(void) + : m_padding("symmetric") { } filter::Filter::Filter(const vector<double> &taps) + : m_padding("symmetric") { setTaps(taps); } @@ -178,6 +180,7 @@ void filter::Filter::dwtCutFrom(const ImgReaderGdal& input, ImgWriterGdal& outpu } } +//todo: support different padding strategies void filter::Filter::dwtForward(std::vector<double>& data, const std::string& wavelet_type, int family){ int origsize=data.size(); //make sure data size if power of 2 @@ -196,6 +199,7 @@ void filter::Filter::dwtForward(std::vector<double>& data, const std::string& wa gsl_wavelet_workspace_free (work); } +//todo: support different padding strategies void filter::Filter::dwtInverse(std::vector<double>& data, const std::string& wavelet_type, int family){ int origsize=data.size(); //make sure data size if power of 2 @@ -213,6 +217,7 @@ void filter::Filter::dwtInverse(std::vector<double>& data, const std::string& wa gsl_wavelet_workspace_free (work); } +//todo: support different padding strategies void filter::Filter::dwtCut(std::vector<double>& data, const std::string& wavelet_type, int family, double cut){ int origsize=data.size(); //make sure data size if power of 2 @@ -241,9 +246,9 @@ void filter::Filter::dwtCut(std::vector<double>& data, const std::string& wavele gsl_wavelet_workspace_free (work); } -void filter::Filter::morphology(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dim, short down, int offset, short verbose) +void filter::Filter::morphology(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dim, short verbose) { - bool bverbose=(verbose>1)? true:false; + // bool bverbose=(verbose>1)? true:false; Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol()); Vector2d<double> lineOutput(input.nrOfBand(),input.nrOfCol()); const char* pszMessage; @@ -258,7 +263,8 @@ void filter::Filter::morphology(const ImgReaderGdal& input, ImgWriterGdal& outpu vector<double> pixelOutput(input.nrOfBand()); for(int x=0;x<input.nrOfCol();++x){ pixelInput=lineInput.selectCol(x); - morphology(pixelInput,pixelOutput,method,dim,down,offset,bverbose); + filter(pixelInput,pixelOutput,method,dim); + // morphology(pixelInput,pixelOutput,method,dim,bverbose); for(int iband=0;iband<input.nrOfBand();++iband) lineOutput[iband][x]=pixelOutput[iband]; } @@ -275,13 +281,13 @@ void filter::Filter::morphology(const ImgReaderGdal& input, ImgWriterGdal& outpu } } -void filter::Filter::smooth(const ImgReaderGdal& input, ImgWriterGdal& output, short dim, short down, int offset) +void filter::Filter::smooth(const ImgReaderGdal& input, ImgWriterGdal& output, short dim) { assert(dim>0); m_taps.resize(dim); for(int itap=0;itap<dim;++itap) m_taps[itap]=1.0/dim; - filter(input,output,down,offset); + filter(input,output); } // void filter::Filter::smoothnodata(const ImgReaderGdal& input, ImgWriterGdal& output, short dim, short down, int offset) @@ -293,7 +299,7 @@ void filter::Filter::smooth(const ImgReaderGdal& input, ImgWriterGdal& output, s // filter(input,output,down,offset); // } -void filter::Filter::filter(const ImgReaderGdal& input, ImgWriterGdal& output, short down, int offset) +void filter::Filter::filter(const ImgReaderGdal& input, ImgWriterGdal& output) { Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol()); Vector2d<double> lineOutput(input.nrOfBand(),input.nrOfCol()); @@ -309,7 +315,7 @@ void filter::Filter::filter(const ImgReaderGdal& input, ImgWriterGdal& output, s vector<double> pixelOutput(input.nrOfBand()); for(int x=0;x<input.nrOfCol();++x){ pixelInput=lineInput.selectCol(x); - filter(pixelInput,pixelOutput,down,offset); + filter(pixelInput,pixelOutput); for(int iband=0;iband<input.nrOfBand();++iband) lineOutput[iband][x]=pixelOutput[iband]; } @@ -326,10 +332,10 @@ void filter::Filter::filter(const ImgReaderGdal& input, ImgWriterGdal& output, s } } -void filter::Filter::stat(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, short down, int offset) +void filter::Filter::stat(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method) { Vector2d<double> lineInput(input.nrOfBand(),input.nrOfCol()); - assert(output.nrOfCol()==(input.nrOfCol()+down-1)/down); + assert(output.nrOfCol()==input.nrOfCol()); vector<double> lineOutput(output.nrOfCol()); statfactory::StatFactory stat; const char* pszMessage; @@ -338,36 +344,32 @@ void filter::Filter::stat(const ImgReaderGdal& input, ImgWriterGdal& output, con double progress=0; pfnProgress(progress,pszMessage,pProgressArg); for(int y=0;y<input.nrOfRow();++y){ - if((y+1+down/2)%down) - continue; for(int iband=0;iband<input.nrOfBand();++iband) input.readData(lineInput[iband],GDT_Float64,y,iband); vector<double> pixelInput(input.nrOfBand()); for(int x=0;x<input.nrOfCol();++x){ - if((x+1+down/2)%down) - continue; pixelInput=lineInput.selectCol(x); switch(getFilterType(method)){ case(filter::median): - lineOutput[(x-offset+down-1)/down]=stat.median(pixelInput); + lineOutput[x]=stat.median(pixelInput); break; case(filter::min): - lineOutput[(x-offset+down-1)/down]=stat.mymin(pixelInput); + lineOutput[x]=stat.mymin(pixelInput); break; case(filter::max): - lineOutput[(x-offset+down-1)/down]=stat.mymax(pixelInput); + lineOutput[x]=stat.mymax(pixelInput); break; case(filter::sum): - lineOutput[(x-offset+down-1)/down]=stat.sum(pixelInput); + lineOutput[x]=stat.sum(pixelInput); break; case(filter::var): - lineOutput[(x-offset+down-1)/down]=stat.var(pixelInput); + lineOutput[x]=stat.var(pixelInput); break; case(filter::stdev): - lineOutput[(x-offset+down-1)/down]=sqrt(stat.var(pixelInput)); + lineOutput[x]=sqrt(stat.var(pixelInput)); break; case(filter::mean): - lineOutput[(x-offset+down-1)/down]=stat.mean(pixelInput); + lineOutput[x]=stat.mean(pixelInput); break; default: std::string errorString="method not supported"; @@ -376,10 +378,10 @@ void filter::Filter::stat(const ImgReaderGdal& input, ImgWriterGdal& output, con } } try{ - output.writeData(lineOutput,GDT_Float64,y/down); + output.writeData(lineOutput,GDT_Float64,y); } catch(string errorstring){ - cerr << errorstring << "in line " << y/down << endl; + cerr << errorstring << "in line " << y << endl; } progress=(1.0+y)/output.nrOfRow(); pfnProgress(progress,pszMessage,pProgressArg); diff --git a/src/algorithms/Filter.h b/src/algorithms/Filter.h index 70955a1..9b12410 100644 --- a/src/algorithms/Filter.h +++ b/src/algorithms/Filter.h @@ -35,12 +35,19 @@ namespace filter enum FILTER_TYPE { median=0, var=1 , min=2, max=3, sum=4, mean=5, minmax=6, dilate=7, erode=8, close=9, open=10, homog=11, sobelx=12, sobely=13, sobelxy=14, sobelyx=-14, smooth=15, density=16, majority=17, mixed=18, smoothnodata=19, threshold=20, ismin=21, ismax=22, heterog=23, order=24, stdev=25, dwt=26, dwti=27, dwt_cut=28, dwt_cut_from=29}; + enum PADDING { symmetric=0, replicate=1, circular=2, constant=3}; + class Filter { public: Filter(void); Filter(const std::vector<double> &taps); virtual ~Filter(){}; + + void setPadding(const std::string& padString){ + m_padding=padString; + }; + static const gsl_wavelet_type* getWaveletType(const std::string waveletType){ if(waveletType=="daubechies") return(gsl_wavelet_daubechies); if(waveletType=="daubechies_centered") return(gsl_wavelet_daubechies_centered); @@ -54,20 +61,21 @@ public: initFilterMap(m_filterMap); return m_filterMap[filterType]; }; + void setTaps(const std::vector<double> &taps, bool normalize=true); void pushClass(short theClass=1){m_class.push_back(theClass);}; void pushMask(short theMask=0){m_mask.push_back(theMask);}; - template<class T> void filter(const std::vector<T>& input, std::vector<T>& output, int down=1, int offset=0); + template<class T> void filter(const std::vector<T>& input, std::vector<T>& output); template<class T> void filter(const std::vector<T>& input, std::vector<T>& output, const std::string& method, int dim); - template<class T> void smooth(const std::vector<T>& input, std::vector<T>& output, short dim, int down=1, int offset=0); - template<class T> void filter(T* input, int inputSize, std::vector<T>& output, int down=1, int offset=0); - template<class T> void smooth(T* input, int inputSize, std::vector<T>& output, short dim, int down=1, int offset=0); - template<class T> void morphology(const std::vector<T>& input, std::vector<T>& output, const std::string& method, int dim, short down=1, int offset=0, bool verbose=false); - void morphology(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dim, short down=1, int offset=0, short verbose=0); - void filter(const ImgReaderGdal& input, ImgWriterGdal& output, short down=1, int offset=0); - void stat(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, short down=1, int offset=0); + template<class T> void smooth(const std::vector<T>& input, std::vector<T>& output, short dim); + template<class T> void filter(T* input, int inputSize, std::vector<T>& output); + template<class T> void smooth(T* input, int inputSize, std::vector<T>& output, short dim); + //template<class T> void morphology(const std::vector<T>& input, std::vector<T>& output, const std::string& method, int dim, bool verbose=false); + void morphology(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dim, short verbose=0); + void filter(const ImgReaderGdal& input, ImgWriterGdal& output); + void stat(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method); void filter(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dim); - void smooth(const ImgReaderGdal& input, ImgWriterGdal& output, short dim, short down=1, int offset=0); + void smooth(const ImgReaderGdal& input, ImgWriterGdal& output, short dim); double getCentreWavelength(const std::vector<double> &wavelengthIn, const Vector2d<double>& srf, const std::string& interpolationType, double delta=1.0, bool verbose=false); template<class T> double applySrf(const std::vector<double> &wavelengthIn, const std::vector<T>& input, const Vector2d<double>& srf, const std::string& interpolationType, T& output, double delta=1.0, bool normalize=false, bool verbose=false); template<class T> double applySrf(const std::vector<double> &wavelengthIn, const Vector2d<T>& input, const Vector2d<double>& srf, const std::string& interpolationType, std::vector<T>& output, double delta=1.0, bool normalize=false, int down=1, bool transposeInput=false, bool verbose=false); @@ -118,11 +126,24 @@ private: m_filterMap["order"]=filter::order; m_filterMap["median"]=filter::median; } + + + static PADDING getPadding(const std::string& padString){ + std::map<std::string, PADDING> padMap; + padMap["constant"]=filter::constant; + padMap["symmetric"]=filter::symmetric; + padMap["replicate"]=filter::replicate; + padMap["circular"]=filter::circular; + return(padMap[padString]); + }; + std::vector<double> m_taps; std::vector<short> m_class; std::vector<short> m_mask; + std::string m_padding; }; + //input[band], output //returns wavelength for which srf is maximum template<class T> double Filter::applySrf(const std::vector<double> &wavelengthIn, const std::vector<T>& input, const Vector2d<double>& srf, const std::string& interpolationType, T& output, double delta, bool normalize, bool verbose) @@ -195,15 +216,6 @@ private: gsl_spline_free(splineOut); gsl_interp_accel_free(accOut); - // double maxResponse=0; - // int maxIndex=0; - // for(int index=0;index<srf[1].size();++index){ - // if(maxResponse<srf[1][index]){ - // maxResponse=srf[1][index]; - // maxIndex=index; - // } - // } - // return(srf[0][maxIndex]); return(centreWavelength); } @@ -291,15 +303,6 @@ private: gsl_spline_free(splineOut); gsl_interp_accel_free(accOut); - // double maxResponse=0; - // int maxIndex=0; - // for(int index=0;index<srf[1].size();++index){ - // if(maxResponse<srf[1][index]){ - // maxResponse=srf[1][index]; - // maxIndex=index; - // } - // } - // return(srf[0][maxIndex]); return(centreWavelength); } @@ -405,51 +408,88 @@ template<class T> void Filter::applyFwhm(const std::vector<double> &wavelengthIn } } - template<class T> void Filter::smooth(const std::vector<T>& input, std::vector<T>& output, short dim, int down, int offset) + template<class T> void Filter::smooth(const std::vector<T>& input, std::vector<T>& output, short dim) { assert(dim>0); m_taps.resize(dim); for(int itap=0;itap<dim;++itap) m_taps[itap]=1.0/dim; - filter(input,output,down,offset); + filter(input,output); } -template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T>& output, int down, int offset) +template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T>& output) { - output.resize((input.size()-offset+down-1)/down); + assert(input.size()>m_taps.size()); + output.resize(input.size()); int i=0; - //start: extend input with mirrored version of itself - for(i=offset;i<m_taps.size()/2;++i){ - if((i-offset)%down) - continue; + //start: extend input by padding + for(i=0;i<m_taps.size()/2;++i){ //todo:introduce nodata - output[(i-offset+down-1)/down]=m_taps[m_taps.size()/2]*input[i]; - for(int t=1;t<=m_taps.size()/2;++t) - output[(i-offset+down-1)/down]+=(m_taps[m_taps.size()/2+t]+m_taps[m_taps.size()/2-t])*input[i+t]; + output[i]=m_taps[m_taps.size()/2]*input[i]; + for(int t=1;t<=m_taps.size()/2;++t){ + output[i]+=m_taps[m_taps.size()/2+t]*input[i+t]; + if(i>=t) + output[i]+=m_taps[m_taps.size()/2-t]*input[i-t]; + else{ + switch(getPadding(m_padding)){ + case(replicate): + output[i]+=m_taps[m_taps.size()/2-t]*input[0]; + break; + case(circular): + output[i]+=m_taps[m_taps.size()/2-t]*input[input.size()+i-t]; + break; + case(constant): + output[i]+=m_taps[m_taps.size()/2-t]*0; + break; + case(symmetric): + default: + output[i]+=m_taps[m_taps.size()/2-t]*input[t-i]; + break; + } + } + } } //main - for(i=offset+m_taps.size()/2;i<input.size()-m_taps.size()/2;++i){ - if((i-offset)%down) - continue; + for(i=m_taps.size()/2;i<input.size()-m_taps.size()/2;++i){ //todo:introduce nodata T leaveOut=(*(m_taps.begin()))*input[i-m_taps.size()/2]; T include=(m_taps.back())*input[i+m_taps.size()/2]; - output[(i-offset+down-1)/down]=0; + output[i]=0; for(int t=0;t<m_taps.size();++t) - output[(i-offset+down-1)/down]+=input[i-m_taps.size()/2+t]*m_taps[t]; + output[i]+=input[i-m_taps.size()/2+t]*m_taps[t]; } - //end: extend input with mirrored version of itself + //end: extend input by padding for(i=input.size()-m_taps.size()/2;i<input.size();++i){ - if((i-offset)%down) - continue; //todo:introduce nodata - output[(i-offset+down-1)/down]=m_taps[m_taps.size()/2]*input[i]; + output[i]=m_taps[m_taps.size()/2]*input[i]; //todo:introduce nodata - for(int t=1;t<=m_taps.size()/2;++t) - output[(i-offset+down-1)/down]+=(m_taps[m_taps.size()/2+t]+m_taps[m_taps.size()/2-t])*input[i-t]; + for(int t=1;t<=m_taps.size()/2;++t){ + output[i]+=m_taps[m_taps.size()/2-t]*input[i-t]; + if(i+t<input.size()) + output[i]+=m_taps[m_taps.size()/2+t]*input[i+t]; + else{ + switch(getPadding(m_padding)){ + case(replicate): + output[i]+=m_taps[m_taps.size()/2+t]*input.back(); + break; + case(circular): + output[i]+=m_taps[m_taps.size()/2+t]*input[t-1]; + break; + case(constant): + output[i]+=m_taps[m_taps.size()/2+t]*0; + break; + case(symmetric): + default: + output[i]+=m_taps[m_taps.size()/2+t]*input[i-t]; + break; + } + } + //output[i]+=(m_taps[m_taps.size()/2+t]+m_taps[m_taps.size()/2-t])*input[i-t]; + } } } +//todo: filling statBuffer can be optimized (no need to clear and fill entire buffer, just push back new value...) template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T>& output, const std::string& method, int dim) { bool verbose=false; @@ -459,7 +499,7 @@ template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T statfactory::StatFactory stat; std::vector<T> statBuffer; short binValue=0; - //start: extend input with mirrored version of itself + //start: extend input by padding for(i=0;i<dim/2;++i){ binValue=0; for(int iclass=0;iclass<m_class.size();++iclass){ @@ -472,36 +512,62 @@ template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T statBuffer.push_back(binValue); else statBuffer.push_back(input[i]); + for(int t=1;t<=dim/2;++t){ - binValue=0; + T theValue=input[i+t]; for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i+t]==m_class[iclass]){ + if(theValue==m_class[iclass]){ binValue=m_class[0]; break; } } - if(m_class.size()){ - statBuffer.push_back(binValue); - statBuffer.push_back(binValue); + if(m_class.size()) + statBuffer.push_back(binValue); + else + statBuffer.push_back(theValue); + + if(i>=t){ + theValue=input[i-t]; } else{ - statBuffer.push_back(input[i+t]); - statBuffer.push_back(input[i+t]); + switch(getPadding(m_padding)){ + case(replicate): + theValue=input[0]; + break; + case(circular): + theValue=input[input.size()+i-t]; + break; + case(constant): + theValue=0; + break; + case(symmetric): + default: + theValue=input[t-i]; + break; + } + } + for(int iclass=0;iclass<m_class.size();++iclass){ + if(theValue==m_class[iclass]){ + binValue=m_class[0]; + break; + } } + if(m_class.size()) + statBuffer.push_back(binValue); + else + statBuffer.push_back(theValue); } - /* assert(statBuffer.size()==dim); */ - /* if((i-offset)%down){ */ - /* statBuffer.clear(); */ - /* continue; */ - /* } */ + switch(getFilterType(method)){ case(filter::median): output[i]=stat.median(statBuffer); break; case(filter::min): + case(filter::erode): output[i]=stat.mymin(statBuffer); break; case(filter::max): + case(filter::dilate): output[i]=stat.mymax(statBuffer); break; case(filter::sum): @@ -535,15 +601,16 @@ template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T else statBuffer.push_back(input[i-dim/2+t]); } - /* assert(statBuffer.size()==dim); */ switch(getFilterType(method)){ case(filter::median): output[i]=stat.median(statBuffer); break; case(filter::min): + case(filter::erode): output[i]=stat.mymin(statBuffer); break; case(filter::max): + case(filter::dilate): output[i]=stat.mymax(statBuffer); break; case(filter::sum): @@ -562,262 +629,173 @@ template<class T> void Filter::filter(const std::vector<T>& input, std::vector<T } statBuffer.clear(); } - //end: extend input with mirrored version of itself + //end: extend input by padding for(i=input.size()-dim/2;i<input.size();++i){ - binValue=0; - for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i]==m_class[iclass]){ - binValue=m_class[0]; - break; - } - } - if(m_class.size()) - statBuffer.push_back(binValue); - else - statBuffer.push_back(input[i]); - for(int t=1;t<=dim/2;++t){ - binValue=0; - for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i-t]==m_class[iclass]){ - binValue=m_class[0]; - break; - } - } - if(m_class.size()){ - statBuffer.push_back(binValue); - statBuffer.push_back(binValue); - } - else{ - statBuffer.push_back(input[i-t]); - statBuffer.push_back(input[i-t]); - } - } - switch(getFilterType(method)){ - case(filter::median): - output[i]=stat.median(statBuffer); - break; - case(filter::min): - output[i]=stat.mymin(statBuffer); - break; - case(filter::max): - output[i]=stat.mymax(statBuffer); - break; - case(filter::sum): - output[i]=sqrt(stat.sum(statBuffer)); - break; - case(filter::var): - output[i]=stat.var(statBuffer); - break; - case(filter::mean): - output[i]=stat.mean(statBuffer); - break; - default: - std::string errorString="method not supported"; - throw(errorString); - break; - } - } -} - - //todo: this function is redundant, can be incorporated within filter -template<class T> void Filter::morphology(const std::vector<T>& input, std::vector<T>& output, const std::string& method, int dim, short down, int offset, bool verbose) -{ - assert(dim); - output.resize((input.size()-offset+down-1)/down); - int i=0; - statfactory::StatFactory stat; - std::vector<T> statBuffer; - short binValue=0; - //start: extend input with mirrored version of itself - for(i=offset;i<dim/2;++i){ binValue=0; for(int iclass=0;iclass<m_class.size();++iclass){ if(input[i]==m_class[iclass]){ - binValue=m_class[0]; - break; + binValue=m_class[0]; + break; } } if(m_class.size()) statBuffer.push_back(binValue); else statBuffer.push_back(input[i]); + for(int t=1;t<=dim/2;++t){ - binValue=0; + T theValue=input[i-t]; for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i+t]==m_class[iclass]){ - binValue=m_class[0]; - break; - } - } - if(m_class.size()){ - statBuffer.push_back(binValue); - statBuffer.push_back(binValue); + if(theValue==m_class[iclass]){ + binValue=m_class[0]; + break; + } } + if(m_class.size()) + statBuffer.push_back(binValue); + else + statBuffer.push_back(theValue); + if(i+t<input.size()) + theValue=input[i+t]; else{ - statBuffer.push_back(input[i+t]); - statBuffer.push_back(input[i+t]); + switch(getPadding(m_padding)){ + case(replicate): + theValue=input.back(); + break; + case(circular): + theValue=input[t-1]; + break; + case(constant): + theValue=0; + break; + case(symmetric): + default: + theValue=input[i-t]; + break; + } } - } - /* assert(statBuffer.size()==dim); */ - if((i-offset)%down){ - statBuffer.clear(); - continue; - } - switch(getFilterType(method)){ - case(filter::dilate): - output[(i-offset+down-1)/down]=stat.mymax(statBuffer); - break; - case(filter::erode): - output[(i-offset+down-1)/down]=stat.mymin(statBuffer); - break; - default: - std::string errorString="method not supported"; - throw(errorString); - break; - } - if(verbose){ - std::cout << "buffer: "; - for(int ibuf=0;ibuf<statBuffer.size();++ibuf) - std::cout << statBuffer[ibuf] << " "; - std::cout << "->" << output[(i-offset+down-1)/down] << std::endl; - } - } - //main - statBuffer.clear(); - for(i=offset+dim/2;i<input.size()-dim/2;++i){ - binValue=0; - for(int t=0;t<dim;++t){ for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i-dim/2+t]==m_class[iclass]){ - binValue=m_class[0]; - break; - } + if(theValue==m_class[iclass]){ + binValue=m_class[0]; + break; + } } if(m_class.size()) - statBuffer.push_back(binValue); + statBuffer.push_back(binValue); else - statBuffer.push_back(input[i-dim/2+t]); - } - /* assert(statBuffer.size()==dim); */ - if((i-offset)%down){ - statBuffer.clear(); - continue; + statBuffer.push_back(theValue); } switch(getFilterType(method)){ - case(filter::dilate): - output[(i-offset+down-1)/down]=stat.mymax(statBuffer); + case(filter::median): + output[i]=stat.median(statBuffer); break; + case(filter::min): case(filter::erode): - output[(i-offset+down-1)/down]=stat.mymin(statBuffer); - break; - default: - std::string errorString="method not supported"; - throw(errorString); + output[i]=stat.mymin(statBuffer); break; - } - if(verbose){ - std::cout << "buffer: "; - for(int ibuf=0;ibuf<statBuffer.size();++ibuf) - std::cout << statBuffer[ibuf] << " "; - std::cout << "->" << output[(i-offset+down-1)/down] << std::endl; - } - statBuffer.clear(); - } - //end: extend input with mirrored version of itself - for(i=input.size()-dim/2;i<input.size();++i){ - binValue=0; - for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i]==m_class[iclass]){ - binValue=m_class[0]; - break; - } - } - if(m_class.size()) - statBuffer.push_back(binValue); - else - statBuffer.push_back(input[i]); - for(int t=1;t<=dim/2;++t){ - binValue=0; - for(int iclass=0;iclass<m_class.size();++iclass){ - if(input[i-t]==m_class[iclass]){ - binValue=m_class[0]; - break; - } - } - if(m_class.size()){ - statBuffer.push_back(binValue); - statBuffer.push_back(binValue); - } - else{ - statBuffer.push_back(input[i-t]); - statBuffer.push_back(input[i-t]); - } - } - if((i-offset)%down){ - statBuffer.clear(); - continue; - } - switch(getFilterType(method)){ + case(filter::max): case(filter::dilate): - output[(i-offset+down-1)/down]=stat.mymax(statBuffer); + output[i]=stat.mymax(statBuffer); break; - case(filter::erode): - output[(i-offset+down-1)/down]=stat.mymin(statBuffer); + case(filter::sum): + output[i]=sqrt(stat.sum(statBuffer)); + break; + case(filter::var): + output[i]=stat.var(statBuffer); + break; + case(filter::mean): + output[i]=stat.mean(statBuffer); break; default: std::string errorString="method not supported"; throw(errorString); break; } - if(verbose){ - std::cout << "buffer: "; - for(int ibuf=0;ibuf<statBuffer.size();++ibuf) - std::cout << statBuffer[ibuf] << " "; - std::cout << "->" << output[(i-offset+down-1)/down] << std::endl; - } } -} + } - template<class T> void Filter::smooth(T* input, int inputSize, std::vector<T>& output, short dim, int down, int offset) + template<class T> void Filter::smooth(T* input, int inputSize, std::vector<T>& output, short dim) { assert(dim>0); m_taps.resize(dim); for(int itap=0;itap<dim;++itap) m_taps[itap]=1.0/dim; - filter(input,output,down,offset); + filter(input,output); } -template<class T> void Filter::filter(T* input, int inputSize, std::vector<T>& output, int down, int offset) +template<class T> void Filter::filter(T* input, int inputSize, std::vector<T>& output) { - output.resize((inputSize-offset+down-1)/down); + assert(inputSize>m_taps.size()); + output.resize(inputSize); int i=0; - //start: extend input with mirrored version of itself - for(i=offset;i<m_taps.size()/2;++i){ - if((i-offset)%down) - continue; - output[(i-offset+down-1)/down]=m_taps[m_taps.size()/2]*input[i]; - for(int t=1;t<=m_taps.size()/2;++t) - output[(i-offset+down-1)/down]+=(m_taps[m_taps.size()/2+t]+m_taps[m_taps.size()/2-t])*input[i+t]; + + //start: extend input by padding + for(i=0;i<m_taps.size()/2;++i){ + //todo:introduce nodata + output[i]=m_taps[m_taps.size()/2]*input[i]; + + for(int t=1;t<=m_taps.size()/2;++t){ + output[i]+=m_taps[m_taps.size()/2+t]*input[i+t]; + if(i>=t) + output[i]+=m_taps[m_taps.size()/2-t]*input[i-t]; + else{ + switch(getPadding(m_padding)){ + case(replicate): + output[i]+=m_taps[m_taps.size()/2-t]*input[0]; + break; + case(circular): + output[i]+=m_taps[m_taps.size()/2-t]*input[input.size()+i-t]; + break; + case(constant): + output[i]+=m_taps[m_taps.size()/2-t]*0; + break; + case(symmetric): + default: + output[i]+=m_taps[m_taps.size()/2-t]*input[t-i]; + break; + } + } + } } //main - for(i=offset+m_taps.size()/2;i<inputSize-m_taps.size()/2;++i){ - if((i-offset)%down) - continue; + for(i=m_taps.size()/2;i<input.size()-m_taps.size()/2;++i){ + //todo:introduce nodata T leaveOut=(*(m_taps.begin()))*input[i-m_taps.size()/2]; T include=(m_taps.back())*input[i+m_taps.size()/2]; - output[(i-offset+down-1)/down]=0; + output[i]=0; for(int t=0;t<m_taps.size();++t) - output[(i-offset+down-1)/down]+=input[i-m_taps.size()/2+t]*m_taps[t]; + output[i]+=input[i-m_taps.size()/2+t]*m_taps[t]; } - //end: extend input with mirrored version of itself - for(i=inputSize-m_taps.size()/2;i<inputSize;++i){ - if((i-offset)%down) - continue; - output[(i-offset+down-1)/down]=m_taps[m_taps.size()/2]*input[i]; - for(int t=1;t<=m_taps.size()/2;++t) - output[(i-offset+down-1)/down]+=(m_taps[m_taps.size()/2+t]+m_taps[m_taps.size()/2-t])*input[i-t]; + //end: extend input by padding + for(i=input.size()-m_taps.size()/2;i<input.size();++i){ + //todo:introduce nodata + output[i]=m_taps[m_taps.size()/2]*input[i]; + //todo:introduce nodata + for(int t=1;t<=m_taps.size()/2;++t){ + output[i]+=m_taps[m_taps.size()/2-t]*input[i-t]; + if(i+t<input.size()) + output[i]+=m_taps[m_taps.size()/2+t]*input[i+t]; + else{ + switch(getPadding(m_padding)){ + case(replicate): + output[i]+=m_taps[m_taps.size()/2+t]*input.back(); + break; + case(circular): + output[i]+=m_taps[m_taps.size()/2+t]*input[t-1]; + break; + case(constant): + output[i]+=m_taps[m_taps.size()/2+t]*0; + break; + case(symmetric): + default: + output[i]+=m_taps[m_taps.size()/2+t]*input[i-t]; + break; + } + } + } } } + } #endif /* _MYFILTER_H_ */ diff --git a/src/algorithms/ImgRegression.cc b/src/algorithms/ImgRegression.cc index 55b3c2f..e1de847 100644 --- a/src/algorithms/ImgRegression.cc +++ b/src/algorithms/ImgRegression.cc @@ -81,7 +81,7 @@ double ImgRegression::getRMSE(const ImgReaderGdal& imgReader1, const ImgReaderGd } } double err=0; - if(buffer1.size()||buffer2.size()){ + if(buffer1.size()&&buffer2.size()){ statfactory::StatFactory stat; err=stat.linear_regression_err(buffer1,buffer2,c0,c1); } diff --git a/src/apps/pkcomposite.cc b/src/apps/pkcomposite.cc index f53135a..0854009 100644 --- a/src/apps/pkcomposite.cc +++ b/src/apps/pkcomposite.cc @@ -627,8 +627,8 @@ int main(int argc, char *argv[]) val_new=(readCol-0.5-lowerCol)*readBuffer[iband][upperCol-startCol]+(1-readCol+0.5+lowerCol)*readBuffer[iband][lowerCol-startCol]; writeBuffer[iband][ib]=val_new; } - // fileBuffer[ib]=ifile; - ++fileBuffer[ib]; + fileBuffer[ib]=ifile; + // ++fileBuffer[ib]; } break; default: @@ -642,8 +642,8 @@ int main(int argc, char *argv[]) val_new=readBuffer[iband][readCol-startCol]; writeBuffer[iband][ib]=val_new; } - ++fileBuffer[ib]; - // fileBuffer[ib]=ifile; + fileBuffer[ib]=ifile; + // ++fileBuffer[ib]; } break; } diff --git a/src/apps/pkfilter.cc b/src/apps/pkfilter.cc index 4018896..21d43cc 100644 --- a/src/apps/pkfilter.cc +++ b/src/apps/pkfilter.cc @@ -54,6 +54,7 @@ int main(int argc,char **argv) { Optionpk<short> nodata_opt("nodata", "nodata", "nodata value(s) for smoothnodata filter"); Optionpk<std::string> tap_opt("tap", "tap", "text file containing taps used for spatial filtering (from ul to lr). Use dimX and dimY to specify tap dimensions in x and y. Leave empty for not using taps"); Optionpk<double> tapz_opt("tapz", "tapz", "taps used for spectral filtering"); + Optionpk<string> padding_opt("pad","pad", "Padding method for filtering (how to handle edge effects). Choose between: symmetric, replicate, circular, constant (pad with 0).", "symmetric"); Optionpk<double> fwhm_opt("fwhm", "fwhm", "list of full width half to apply spectral filtering (-fwhm band1 -fwhm band2 ...)"); Optionpk<std::string> srf_opt("srf", "srf", "list of ASCII files containing spectral response functions (two columns: wavelength response)"); Optionpk<double> wavelengthIn_opt("win", "wavelengthIn", "list of wavelengths in input spectrum (-win band1 -win band2 ...)"); @@ -92,6 +93,7 @@ int main(int argc,char **argv) { nodata_opt.retrieveOption(argc,argv); tap_opt.retrieveOption(argc,argv); tapz_opt.retrieveOption(argc,argv); + padding_opt.retrieveOption(argc,argv); fwhm_opt.retrieveOption(argc,argv); srf_opt.retrieveOption(argc,argv); wavelengthIn_opt.retrieveOption(argc,argv); @@ -222,6 +224,9 @@ int main(int argc,char **argv) { filter2d::Filter2d filter2d; filter::Filter filter1d; + if(verbose_opt[0]) + cout << "Set padding to " << padding_opt[0] << endl; + filter1d.setPadding(padding_opt[0]); if(class_opt.size()){ if(verbose_opt[0]) std::cout<< "class values: "; @@ -278,7 +283,7 @@ int main(int argc,char **argv) { std::cout<< std::endl; } filter1d.setTaps(tapz_opt); - filter1d.filter(input,output,down_opt[0]); + filter1d.filter(input,output); } else if(fwhm_opt.size()){ if(verbose_opt[0]) @@ -385,7 +390,7 @@ int main(int argc,char **argv) { if(dimZ_opt.size()){ if(verbose_opt[0]) std::cout<< "1-D filtering: dilate" << std::endl; - filter1d.morphology(input,output,"dilate",dimZ_opt[0],1,0,verbose_opt[0]); + filter1d.morphology(input,output,"dilate",dimZ_opt[0],verbose_opt[0]); } else{ filter2d.morphology(input,output,"dilate",dimX_opt[0],dimY_opt[0],angle_opt,disc_opt[0]); @@ -710,7 +715,7 @@ int main(int argc,char **argv) { default: if(dimZ_opt.size()){ if(dimZ_opt[0]==1) - filter1d.stat(input,output,method_opt[0],down_opt[0]); + filter1d.stat(input,output,method_opt[0]); else{ assert(down_opt[0]==1);//not implemented yet... filter1d.filter(input,output,method_opt[0],dimZ_opt[0]); diff --git a/src/apps/pkkalman.cc b/src/apps/pkkalman.cc index eff5c4e..04daa31 100644 --- a/src/apps/pkkalman.cc +++ b/src/apps/pkkalman.cc @@ -41,7 +41,6 @@ int main(int argc,char **argv) { Optionpk<string> outputfw_opt("ofw", "outputfw", "Output raster dataset for forward model"); Optionpk<string> outputbw_opt("obw", "outputbw", "Output raster dataset for backward model"); Optionpk<string> outputfb_opt("ofb", "outputfb", "Output raster dataset for smooth model"); - Optionpk<float> threshold_opt("th", "threshold", "threshold for selecting samples (randomly). Provide probability in percentage (>0) or absolute (<0).", 0); Optionpk<double> modnodata_opt("modnodata", "modnodata", "invalid value for model input", 0); Optionpk<double> obsnodata_opt("obsnodata", "obsnodata", "invalid value for observation input", 0); Optionpk<double> modoffset_opt("modoffset", "modoffset", "offset used to read model input dataset (value=offset+scale*readValue", 0); @@ -55,6 +54,9 @@ int main(int argc,char **argv) { // Optionpk<double> regTime_opt("rt", "regtime", "Relative Weight for regression in time series", 1.0); // Optionpk<double> regSensor_opt("rs", "regsensor", "Relative Weight for regression in sensor series", 1.0); Optionpk<int> down_opt("down", "down", "Downsampling factor for reading model data to calculate regression", 9); + Optionpk<float> threshold_opt("th", "threshold", "threshold for selecting samples (randomly). Provide probability in percentage (>0) or absolute (<0).", 0); + Optionpk<int> minreg_opt("minreg", "minreg", "Minimum number of pixels to take into account for regression", 5, 2); + Optionpk<unsigned short> window_opt("win", "window", "window size for calculating regression (use 0 for global)", 0); Optionpk<string> oformat_opt("of", "oformat", "Output image format (see also gdal_translate). Empty string: inherit from input image","GTiff",2); Optionpk<string> option_opt("co", "co", "Creation option for output file. Multiple options can be specified."); Optionpk<short> verbose_opt("v", "verbose", "verbose mode when positive", 0); @@ -70,7 +72,6 @@ int main(int argc,char **argv) { outputfw_opt.retrieveOption(argc,argv); outputbw_opt.retrieveOption(argc,argv); outputfb_opt.retrieveOption(argc,argv); - threshold_opt.retrieveOption(argc,argv); modnodata_opt.retrieveOption(argc,argv); obsnodata_opt.retrieveOption(argc,argv); modoffset_opt.retrieveOption(argc,argv); @@ -84,6 +85,9 @@ int main(int argc,char **argv) { // regTime_opt.retrieveOption(argc,argv); // regSensor_opt.retrieveOption(argc,argv); down_opt.retrieveOption(argc,argv); + threshold_opt.retrieveOption(argc,argv); + minreg_opt.retrieveOption(argc,argv); + window_opt.retrieveOption(argc,argv); oformat_opt.retrieveOption(argc,argv); option_opt.retrieveOption(argc,argv); verbose_opt.retrieveOption(argc,argv); @@ -156,6 +160,7 @@ int main(int argc,char **argv) { } statfactory::StatFactory stat; + stat.setNoDataValues(modnodata_opt); imgregression::ImgRegression imgreg; // vector<ImgReaderGdal> imgReaderModel(model_opt.size()); // vector<ImgReaderGdal> imgReaderObs(observation_opt.size()); @@ -194,6 +199,11 @@ int main(int argc,char **argv) { imgreg.setDown(down_opt[0]); imgreg.setThreshold(threshold_opt[0]); + double c0modGlobal=0;//time regression coefficient c0 calculated on entire image + double c1modGlobal=0;//time regression coefficient c1 calculated on entire image + double c0mod=0;//time regression coefficient c0 calculated on local window + double c1mod=0;//time regression coefficient c1 calculated on local window + double c0obs=0; double c1obs=0; double errObs=uncertNodata_opt[0];//start with high initial value in case we do not have first observation at time 0 @@ -403,14 +413,12 @@ int main(int argc,char **argv) { //to keep it general, we must redo it (overlap might have changed) pfnProgress(progress,pszMessage,pProgressArg); - double c0mod=0; - double c1mod=0; if(verbose_opt[0]) cout << "Calculating regression for " << imgReaderModel1.getFileName() << " " << imgReaderModel2.getFileName() << endl; - double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0mod,c1mod); - // double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0mod,c1mod,verbose_opt[0]); + double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal); + // double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal,verbose_opt[0]); bool update=false; if(obsindex<relobsindex.size()){ @@ -446,50 +454,125 @@ int main(int argc,char **argv) { imgReaderEst.setOffset(obsoffset_opt[0]); imgReaderEst.setScale(obsscale_opt[0]); - vector<double> obsBuffer; - vector<double> modelBuffer; - vector<double> uncertObsBuffer; + vector<double> obsLineBuffer; + vector<double> obsWindowBuffer;//buffer for observation to calculate average corresponding to model pixel + vector<double> model1LineBuffer; + vector<double> model2LineBuffer; + vector<double> model1buffer;//buffer for model 1 to calculate time regression based on window + vector<double> model2buffer;//buffer for model 2 to calculate time regression based on window + vector<double> uncertObsLineBuffer; vector<double> estReadBuffer; + vector<double> estWindowBuffer;//buffer for estimate to calculate average corresponding to model pixel vector<double> uncertReadBuffer; vector<double> estWriteBuffer(ncol); vector<double> uncertWriteBuffer(ncol); for(int irow=0;irow<imgWriterEst.nrOfRow();++irow){ assert(irow<imgReaderEst.nrOfRow()); - imgReaderEst.readData(estReadBuffer,GDT_Float64,irow,0); + //not needed here, because we read entire window for each pixel... + // imgReaderEst.readData(estReadBuffer,GDT_Float64,irow,0); imgReaderEst.readData(uncertReadBuffer,GDT_Float64,irow,1); //read model2 in case current estimate is nodata imgReaderEst.image2geo(0,irow,x,y); imgReaderModel2.geo2image(x,y,modCol,modRow); assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow()); - imgReaderModel2.readData(modelBuffer,GDT_Float64,modRow,0); + imgReaderModel2.readData(model2LineBuffer,GDT_Float64,modRow,0); + + imgReaderModel1.geo2image(x,y,modCol,modRow); + assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow()); + imgReaderModel1.readData(model1LineBuffer,GDT_Float64,modRow,0); + if(update){ - imgReaderObs.readData(obsBuffer,GDT_Float64,irow,0); + imgReaderObs.readData(obsLineBuffer,GDT_Float64,irow,0); if(imgReaderObs.nrOfBand()>1) - imgReaderObs.readData(uncertObsBuffer,GDT_Float64,irow,1); + imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1); } for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){ - double estValue=estReadBuffer[icol]; + int minCol=(icol>down_opt[0]/2) ? icol-down_opt[0]/2 : 0; + int maxCol=(icol+down_opt[0]/2<imgReaderEst.nrOfCol()) ? icol+down_opt[0]/2 : imgReaderEst.nrOfCol()-1; + int minRow=(irow>down_opt[0]/2) ? irow-down_opt[0]/2 : 0; + int maxRow=(irow+down_opt[0]/2<imgReaderEst.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderEst.nrOfRow()-1; + imgReaderEst.readDataBlock(estWindowBuffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0); + double estMeanValue=stat.mean(estWindowBuffer); + // double estValue=estReadBuffer[icol]; + double estValue=estWindowBuffer[estWindowBuffer.size()/2]; //time update - if(imgReaderEst.isNoData(estValue)){ - //pk: in case we have not found any valid data yet, better here to take the current model value + imgReaderEst.image2geo(0,irow,x,y); + imgReaderModel1.geo2image(x,y,modCol,modRow); + double difference=(estMeanValue-c0obs)/c1obs-model1LineBuffer[modCol]; + difference*=difference; + bool estNodata=(sqrt(difference)>uncertModel_opt[0]*stdDev); + estNodata=estNodata||imgReaderEst.isNoData(estValue); + if(estNodata){ imgReaderEst.image2geo(icol,irow,x,y); imgReaderModel2.geo2image(x,y,modCol,modRow); assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow()); - if(imgReaderModel2.isNoData(modelBuffer[modCol])){//if both estimate and model are no-data, set obs to nodata + //pk: in case we have not found any valid data yet, better here to take the current model value + if(imgReaderModel2.isNoData(model2LineBuffer[modCol])){//if both estimate and model are no-data, set obs to nodata estWriteBuffer[icol]=obsnodata_opt[0]; uncertWriteBuffer[icol]=uncertNodata_opt[0]; } else{ - estWriteBuffer[icol]=modelBuffer[modCol]; + estWriteBuffer[icol]=model2LineBuffer[modCol]; uncertWriteBuffer[icol]=uncertModel_opt[0]*stdDev; } } else{ + if(window_opt[0]>0){ + try{ + imgReaderEst.image2geo(icol,irow,x,y); + imgReaderModel1.geo2image(x,y,modCol,modRow); + assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow()); + minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0; + maxCol=(modCol+window_opt[0]/2<imgReaderModel1.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel1.nrOfCol()-1; + minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0; + maxRow=(modRow+window_opt[0]/2<imgReaderModel1.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel1.nrOfRow()-1; + imgReaderModel1.readDataBlock(model1buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0); + imgReaderEst.image2geo(icol,irow,x,y); + + imgReaderModel2.geo2image(x,y,modCol,modRow); + assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow()); + minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0; + maxCol=(modCol+window_opt[0]/2<imgReaderModel2.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel2.nrOfCol()-1; + minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0; + maxRow=(modRow+window_opt[0]/2<imgReaderModel2.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel2.nrOfRow()-1; + imgReaderModel2.readDataBlock(model2buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0); + } + catch(string errorString){ + cerr << "Error reading data block for " << minCol << "-" << maxCol << ", " << minRow << "-" << maxRow << endl; + } + //todo: erase non-similar data to observation... + vector<double>::iterator it1=model1buffer.begin(); + vector<double>::iterator it2=model2buffer.begin(); + while(it1!=model1buffer.end()&&it2!=model2buffer.end()){ + //erase nodata + double difference=(estMeanValue-c0obs)/c1obs-*it1; + difference*=difference; + bool modNodata=(sqrt(difference)>uncertModel_opt[0]*stdDev); + modNodata=modNodata||imgReaderModel1.isNoData(*it1); + modNodata=modNodata||imgReaderModel2.isNoData(*it2); + + if(modNodata){ + model1buffer.erase(it1); + model2buffer.erase(it2); + } + else{ + ++it1; + ++it2; + } + } + if(model1buffer.size()>minreg_opt[0]&&model2buffer.size()>minreg_opt[0]) + errMod=stat.linear_regression_err(model1buffer,model2buffer,c0mod,c1mod); + else{//use global regression... + c0mod=c0modGlobal; + c1mod=c1modGlobal; + } + } double certNorm=(errMod*errMod+errObs*errObs); double certMod=errObs*errObs/certNorm; double certObs=errMod*errMod/certNorm; double regTime=(c0mod+c1mod*estValue)*certMod; + //todo: check? estValue is already in the correct scaling from last iteration, see mail to Fer double regSensor=(c0obs+c1obs*estValue)*certObs; estWriteBuffer[icol]=regTime+regSensor; double totalUncertainty=0; @@ -504,15 +587,15 @@ int main(int argc,char **argv) { uncertWriteBuffer[icol]=totalUncertainty+uncertReadBuffer[icol]; } //observation update - if(update&&!imgReaderObs.isNoData(obsBuffer[icol])){ + if(update&&!imgReaderObs.isNoData(obsLineBuffer[icol])){ double kalmanGain=1; double uncertObs=uncertObs_opt[0]; - if(uncertObsBuffer.size()>icol) - uncertObs=uncertObsBuffer[icol]; + if(uncertObsLineBuffer.size()>icol) + uncertObs=uncertObsLineBuffer[icol]; if((uncertWriteBuffer[icol]+uncertObs)>eps_opt[0]) kalmanGain=uncertWriteBuffer[icol]/(uncertWriteBuffer[icol]+uncertObs); assert(kalmanGain<=1); - estWriteBuffer[icol]+=kalmanGain*(obsBuffer[icol]-estWriteBuffer[icol]); + estWriteBuffer[icol]+=kalmanGain*(obsLineBuffer[icol]-estWriteBuffer[icol]); uncertWriteBuffer[icol]*=(1-kalmanGain); } } @@ -589,7 +672,6 @@ int main(int argc,char **argv) { //write last model as output if(verbose_opt[0]) cout << "write last model as output" << endl; - // for(int irow=0;irow<imgWriterEst.nrOfRow();++irow){ for(int irow=0;irow<nrow;++irow){ vector<double> estReadBuffer; vector<double> estWriteBuffer(ncol); @@ -635,10 +717,10 @@ int main(int argc,char **argv) { imgReaderModel1.readData(estReadBuffer,GDT_Float64,modRow); vector<double> estWriteBuffer(ncol); vector<double> uncertWriteBuffer(ncol); - vector<double> uncertObsBuffer; + vector<double> uncertObsLineBuffer; imgReaderObs.readData(estWriteBuffer,GDT_Float64,irow,0); if(imgReaderObs.nrOfBand()>1) - imgReaderObs.readData(uncertObsBuffer,GDT_Float64,irow,1); + imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1); for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){ if(imgReaderObs.isNoData(estWriteBuffer[icol])){ imgWriterEst.image2geo(icol,irow,x,y); @@ -652,8 +734,8 @@ int main(int argc,char **argv) { } else{ double uncertObs=uncertObs_opt[0]; - if(uncertObsBuffer.size()>icol) - uncertObs=uncertObsBuffer[icol]; + if(uncertObsLineBuffer.size()>icol) + uncertObs=uncertObsLineBuffer[icol]; if(uncertModel_opt[0]*stdDev+uncertObs>eps_opt[0]){ imgWriterEst.image2geo(icol,irow,x,y); imgReaderModel1.geo2image(x,y,modCol,modRow); @@ -722,13 +804,12 @@ int main(int argc,char **argv) { //to keep it general, we must redo it (overlap might have changed) pfnProgress(progress,pszMessage,pProgressArg); - double c0mod=0; - double c1mod=0; if(verbose_opt[0]) cout << "Calculating regression for " << imgReaderModel1.getFileName() << " " << imgReaderModel2.getFileName() << endl; - double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0mod,c1mod); - // double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0mod,c1mod,verbose_opt[0]); + + double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal); + // double errMod=imgreg.getRMSE(imgReaderModel1,imgReaderModel2,c0modGlobal,c1modGlobal,verbose_opt[0]); bool update=false; if(obsindex<relobsindex.size()){ @@ -747,6 +828,8 @@ int main(int argc,char **argv) { if(verbose_opt[0]) cout << "Calculating regression for " << imgReaderModel2.getFileName() << " " << imgReaderObs.getFileName() << endl; errObs=imgreg.getRMSE(imgReaderModel2,imgReaderObs,c0obs,c1obs,verbose_opt[0]); + if(verbose_opt[0]) + cout << "c0obs, c1obs: " << c0obs << ", " << c1obs << endl; } //prediction (also to fill cloudy pixels in update mode) string input; @@ -762,57 +845,132 @@ int main(int argc,char **argv) { imgReaderEst.setOffset(obsoffset_opt[0]); imgReaderEst.setScale(obsscale_opt[0]); - vector<double> obsBuffer; - vector<double> modelBuffer; - vector<double> uncertObsBuffer; + vector<double> obsLineBuffer; + vector<double> obsWindowBuffer;//buffer for observation to calculate average corresponding to model pixel + vector<double> model1LineBuffer; + vector<double> model2LineBuffer; + vector<double> model1buffer;//buffer for model 1 to calculate time regression based on window + vector<double> model2buffer;//buffer for model 2 to calculate time regression based on window + vector<double> uncertObsLineBuffer; vector<double> estReadBuffer; + vector<double> estWindowBuffer;//buffer for estimate to calculate average corresponding to model pixel vector<double> uncertReadBuffer; vector<double> estWriteBuffer(ncol); vector<double> uncertWriteBuffer(ncol); - + for(int irow=0;irow<imgWriterEst.nrOfRow();++irow){ assert(irow<imgReaderEst.nrOfRow()); - imgReaderEst.readData(estReadBuffer,GDT_Float64,irow,0); + //not needed here, because we read entire window for each pixel... + // imgReaderEst.readData(estReadBuffer,GDT_Float64,irow,0); imgReaderEst.readData(uncertReadBuffer,GDT_Float64,irow,1); //read model2 in case current estimate is nodata imgReaderEst.image2geo(0,irow,x,y); imgReaderModel2.geo2image(x,y,modCol,modRow); assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow()); - imgReaderModel2.readData(modelBuffer,GDT_Float64,modRow,0); + imgReaderModel2.readData(model2LineBuffer,GDT_Float64,modRow,0); + + imgReaderModel1.geo2image(x,y,modCol,modRow); + assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow()); + imgReaderModel1.readData(model1LineBuffer,GDT_Float64,modRow,0); + if(update){ - imgReaderObs.readData(obsBuffer,GDT_Float64,irow,0); + imgReaderObs.readData(obsLineBuffer,GDT_Float64,irow,0); if(imgReaderObs.nrOfBand()>1) - imgReaderObs.readData(uncertObsBuffer,GDT_Float64,irow,1); + imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1); } for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){ - double estValue=estReadBuffer[icol]; + int minCol=(icol>down_opt[0]/2) ? icol-down_opt[0]/2 : 0; + int maxCol=(icol+down_opt[0]/2<imgReaderEst.nrOfCol()) ? icol+down_opt[0]/2 : imgReaderEst.nrOfCol()-1; + int minRow=(irow>down_opt[0]/2) ? irow-down_opt[0]/2 : 0; + int maxRow=(irow+down_opt[0]/2<imgReaderEst.nrOfRow()) ? irow+down_opt[0]/2 : imgReaderEst.nrOfRow()-1; + imgReaderEst.readDataBlock(estWindowBuffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0); + double estMeanValue=stat.mean(estWindowBuffer); + // double estValue=estReadBuffer[icol]; + double estValue=estWindowBuffer[estWindowBuffer.size()/2]; //time update - if(imgReaderEst.isNoData(estValue)){ - //pk: in case we have not found any valid data yet, better here to take the current model value + imgReaderEst.image2geo(0,irow,x,y); + imgReaderModel1.geo2image(x,y,modCol,modRow); + double difference=(estMeanValue-c0obs)/c1obs-model1LineBuffer[modCol]; + difference*=difference; + bool estNodata=(sqrt(difference)>uncertModel_opt[0]*stdDev); + estNodata=estNodata||imgReaderEst.isNoData(estValue); + if(estNodata){ imgReaderEst.image2geo(icol,irow,x,y); imgReaderModel2.geo2image(x,y,modCol,modRow); assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow()); - if(imgReaderModel2.isNoData(modelBuffer[modCol])){//if both estimate and model are no-data, set obs to nodata + //pk: in case we have not found any valid data yet, better here to take the current model value + if(imgReaderModel2.isNoData(model2LineBuffer[modCol])){//if both estimate and model are no-data, set obs to nodata estWriteBuffer[icol]=obsnodata_opt[0]; uncertWriteBuffer[icol]=uncertNodata_opt[0]; } else{ - estWriteBuffer[icol]=modelBuffer[modCol]; + estWriteBuffer[icol]=model2LineBuffer[modCol]; uncertWriteBuffer[icol]=uncertModel_opt[0]*stdDev; } } else{ + if(window_opt[0]>0){ + try{ + imgReaderEst.image2geo(icol,irow,x,y); + imgReaderModel1.geo2image(x,y,modCol,modRow); + assert(modRow>=0&&modRow<imgReaderModel1.nrOfRow()); + minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0; + maxCol=(modCol+window_opt[0]/2<imgReaderModel1.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel1.nrOfCol()-1; + minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0; + maxRow=(modRow+window_opt[0]/2<imgReaderModel1.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel1.nrOfRow()-1; + imgReaderModel1.readDataBlock(model1buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0); + imgReaderEst.image2geo(icol,irow,x,y); + + imgReaderModel2.geo2image(x,y,modCol,modRow); + assert(modRow>=0&&modRow<imgReaderModel2.nrOfRow()); + minCol=(modCol>window_opt[0]/2) ? modCol-window_opt[0]/2 : 0; + maxCol=(modCol+window_opt[0]/2<imgReaderModel2.nrOfCol()) ? modCol+window_opt[0]/2 : imgReaderModel2.nrOfCol()-1; + minRow=(modRow>window_opt[0]/2) ? modRow-window_opt[0]/2 : 0; + maxRow=(modRow+window_opt[0]/2<imgReaderModel2.nrOfRow()) ? modRow+window_opt[0]/2 : imgReaderModel2.nrOfRow()-1; + imgReaderModel2.readDataBlock(model2buffer,GDT_Float64,minCol,maxCol,minRow,maxRow,0); + } + catch(string errorString){ + cerr << "Error reading data block for " << minCol << "-" << maxCol << ", " << minRow << "-" << maxRow << endl; + } + //todo: erase non-similar data to observation... + vector<double>::iterator it1=model1buffer.begin(); + vector<double>::iterator it2=model2buffer.begin(); + while(it1!=model1buffer.end()&&it2!=model2buffer.end()){ + //erase nodata + double difference=(estMeanValue-c0obs)/c1obs-*it1; + difference*=difference; + bool modNodata=(sqrt(difference)>uncertModel_opt[0]*stdDev); + modNodata=modNodata||imgReaderModel1.isNoData(*it1); + modNodata=modNodata||imgReaderModel2.isNoData(*it2); + + if(modNodata){ + model1buffer.erase(it1); + model2buffer.erase(it2); + } + else{ + ++it1; + ++it2; + } + } + if(model1buffer.size()>minreg_opt[0]&&model2buffer.size()>minreg_opt[5]) + errMod=stat.linear_regression_err(model1buffer,model2buffer,c0mod,c1mod); + else{//use global regression... + c0mod=c0modGlobal; + c1mod=c1modGlobal; + } + } double certNorm=(errMod*errMod+errObs*errObs); double certMod=errObs*errObs/certNorm; double certObs=errMod*errMod/certNorm; double regTime=(c0mod+c1mod*estValue)*certMod; + //todo: check? estValue is already in the correct scaling from last iteration, see mail to Fer double regSensor=(c0obs+c1obs*estValue)*certObs; estWriteBuffer[icol]=regTime+regSensor; double totalUncertainty=0; if(errMod<eps_opt[0]) totalUncertainty=errObs; else if(errObs<eps_opt[0]) - totalUncertainty=errObs; + totalUncertainty=errMod; else{ totalUncertainty=1.0/errMod/errMod+1/errObs/errObs; totalUncertainty=sqrt(1.0/totalUncertainty); @@ -820,15 +978,15 @@ int main(int argc,char **argv) { uncertWriteBuffer[icol]=totalUncertainty+uncertReadBuffer[icol]; } //observation update - if(update&&!imgReaderObs.isNoData(obsBuffer[icol])){ + if(update&&!imgReaderObs.isNoData(obsLineBuffer[icol])){ double kalmanGain=1; double uncertObs=uncertObs_opt[0]; - if(uncertObsBuffer.size()>icol) - uncertObs=uncertObsBuffer[icol]; + if(uncertObsLineBuffer.size()>icol) + uncertObs=uncertObsLineBuffer[icol]; if((uncertWriteBuffer[icol]+uncertObs)>eps_opt[0]) kalmanGain=uncertWriteBuffer[icol]/(uncertWriteBuffer[icol]+uncertObs); assert(kalmanGain<=1); - estWriteBuffer[icol]+=kalmanGain*(obsBuffer[icol]-estWriteBuffer[icol]); + estWriteBuffer[icol]+=kalmanGain*(obsLineBuffer[icol]-estWriteBuffer[icol]); uncertWriteBuffer[icol]*=(1-kalmanGain); } } @@ -907,7 +1065,7 @@ int main(int argc,char **argv) { vector<double> estForwardBuffer; vector<double> estBackwardBuffer; - vector<double> uncertObsBuffer; + vector<double> uncertObsLineBuffer; vector<double> uncertForwardBuffer; vector<double> uncertBackwardBuffer; vector<double> uncertReadBuffer; @@ -943,7 +1101,7 @@ int main(int argc,char **argv) { if(update){ imgReaderObs.readData(estWriteBuffer,GDT_Float64,irow,0); if(imgReaderObs.nrOfBand()>1) - imgReaderObs.readData(uncertObsBuffer,GDT_Float64,irow,1); + imgReaderObs.readData(uncertObsLineBuffer,GDT_Float64,irow,1); } for(int icol=0;icol<imgWriterEst.nrOfCol();++icol){ @@ -956,8 +1114,8 @@ int main(int argc,char **argv) { // if(update){//check for nodata in observation // if(imgReaderObs.isNoData(estWriteBuffer[icol])) // uncertObs=uncertNodata_opt[0]; - // else if(uncertObsBuffer.size()>icol) - // uncertObs=uncertObsBuffer[icol]; + // else if(uncertObsLineBuffer.size()>icol) + // uncertObs=uncertObsLineBuffer[icol]; // } double noemer=(C+D); diff --git a/src/imageclasses/ImgReaderGdal.h b/src/imageclasses/ImgReaderGdal.h index 5d4fceb..d287631 100644 --- a/src/imageclasses/ImgReaderGdal.h +++ b/src/imageclasses/ImgReaderGdal.h @@ -237,14 +237,25 @@ template<typename T> void ImgReaderGdal::readDataBlock(std::vector<T>& buffer, c GDALRasterBand *poBand; assert(band<nrOfBand()+1); poBand = m_gds->GetRasterBand(band+1);//GDAL uses 1 based index - assert(minCol<nrOfCol()); - assert(minCol>=0); - assert(maxCol<nrOfCol()); - assert(minCol<=maxCol); - assert(minRow<nrOfRow()); - assert(minRow>=0); - assert(maxRow<nrOfRow()); - assert(minRow<=maxRow); + if(minCol>=nrOfCol() || + (minCol<0) || + (maxCol>=nrOfCol()) || + (minCol>maxCol) || + (minRow>=nrOfRow()) || + (minRow<0) || + (maxRow>=nrOfRow()) || + (minRow>maxRow)){ + std::string errorString="block not within image boundaries"; + throw(errorString); + } + /* assert(minCol<nrOfCol()); */ + /* assert(minCol>=0); */ + /* assert(maxCol<nrOfCol()); */ + /* assert(minCol<=maxCol); */ + /* assert(minRow<nrOfRow()); */ + /* assert(minRow>=0); */ + /* assert(maxRow<nrOfRow()); */ + /* assert(minRow<=maxRow); */ if(buffer.size()!=(maxRow-minRow+1)*(maxCol-minCol+1)) buffer.resize((maxRow-minRow+1)*(maxCol-minCol+1)); poBand->RasterIO(GF_Read,minCol,minRow,maxCol-minCol+1,maxRow-minRow+1,&(buffer[0]),(maxCol-minCol+1),(maxRow-minRow+1),dataType,0,0); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pktools.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel