pktools  2.6.5
Processing Kernel for geospatial data
Filter2d.cc
1 /**********************************************************************
2 Filter2d.cc: class for filtering images
3 Copyright (C) 2008-2012 Pieter Kempeneers
4 
5 This file is part of pktools
6 
7 pktools is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 pktools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with pktools. If not, see <http://www.gnu.org/licenses/>.
19 ***********************************************************************/
20 #include <sstream>
21 #include <iomanip>
22 #include <iostream>
23 #include <cmath>
24 #include "Filter2d.h"
25 #include "StatFactory.h"
26 // #include "imageclasses/ImgUtils.h"
27 
28 filter2d::Filter2d::Filter2d(void)
29 {
30 }
31 
32 filter2d::Filter2d::Filter2d(const Vector2d<double> &taps)
33  : m_taps(taps)
34 {
35 }
36 
37 int filter2d::Filter2d::pushNoDataValue(double noDataValue)
38 {
39  if(find(m_noDataValues.begin(),m_noDataValues.end(),noDataValue)==m_noDataValues.end())
40  m_noDataValues.push_back(noDataValue);
41  return(m_noDataValues.size());
42 }
43 
44 void filter2d::Filter2d::setTaps(const Vector2d<double> &taps)
45 {
46  m_taps=taps;
47 }
48 
49 void filter2d::Filter2d::smoothNoData(const ImgReaderGdal& input, ImgWriterGdal& output, int dim)
50 {
51  smoothNoData(input, output,dim,dim);
52 }
53 
54 void filter2d::Filter2d::smooth(const ImgReaderGdal& input, ImgWriterGdal& output, int dim)
55 {
56  smooth(input, output,dim,dim);
57 }
58 
59 void filter2d::Filter2d::smoothNoData(const ImgReaderGdal& input, ImgWriterGdal& output, int dimX, int dimY)
60 {
61  m_taps.resize(dimY);
62  for(int j=0;j<dimY;++j){
63  m_taps[j].resize(dimX);
64  for(int i=0;i<dimX;++i)
65  m_taps[j][i]=1.0;
66  }
67  filter(input,output,false,true,true);
68 }
69 
70 void filter2d::Filter2d::smooth(const ImgReaderGdal& input, ImgWriterGdal& output, int dimX, int dimY)
71 {
72  m_taps.resize(dimY);
73  for(int j=0;j<dimY;++j){
74  m_taps[j].resize(dimX);
75  for(int i=0;i<dimX;++i)
76  m_taps[j][i]=1.0;
77  }
78  filter(input,output,false,true,false);
79 }
80 
81 
82 void filter2d::Filter2d::filter(const ImgReaderGdal& input, ImgWriterGdal& output, bool absolute, bool normalize, bool noData)
83 {
84  int dimX=m_taps[0].size();//horizontal!!!
85  int dimY=m_taps.size();//vertical!!!
86  // byte* tmpbuf=new byte[input.rowSize()];
87  const char* pszMessage;
88  void* pProgressArg=NULL;
89  GDALProgressFunc pfnProgress=GDALTermProgress;
90  double progress=0;
91  pfnProgress(progress,pszMessage,pProgressArg);
92  for(int iband=0;iband<input.nrOfBand();++iband){
93  Vector2d<double> inBuffer(dimY,input.nrOfCol());
94  std::vector<double> outBuffer(input.nrOfCol());
95  int indexI=0;
96  int indexJ=0;
97  //initialize last half of inBuffer
98  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
99  try{
100  input.readData(inBuffer[indexJ],GDT_Float64,abs(j),iband);
101  }
102  catch(std::string errorstring){
103  std::cerr << errorstring << "in line " << indexJ << std::endl;
104  }
105  ++indexJ;
106  }
107 
108  for(int y=0;y<input.nrOfRow();++y){
109  if(y){//inBuffer already initialized for y=0
110  //erase first line from inBuffer
111  if(dimY>1)
112  inBuffer.erase(inBuffer.begin());
113  //read extra line and push back to inBuffer if not out of bounds
114  if(y+dimY/2<input.nrOfRow()){
115  //allocate buffer
116  if(dimY>1)
117  inBuffer.push_back(inBuffer.back());
118  try{
119  input.readData(inBuffer[inBuffer.size()-1],GDT_Float64,y+dimY/2,iband);
120  }
121  catch(std::string errorstring){
122  std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
123  }
124  }
125  else{
126  int over=y+dimY/2-input.nrOfRow();
127  int index=(inBuffer.size()-1)-over;
128  assert(index>=0);
129  assert(index<inBuffer.size());
130  inBuffer.push_back(inBuffer[index]);
131  }
132  }
133  for(int x=0;x<input.nrOfCol();++x){
134  outBuffer[x]=0;
135  double norm=0;
136  bool masked=false;
137  if(noData){//only filter noData values
138  for(int imask=0;imask<m_noDataValues.size();++imask){
139  if(inBuffer[(dimY-1)/2][x]==m_noDataValues[imask]){
140  masked=true;
141  break;
142  }
143  }
144  if(!masked){
145  outBuffer[x]=inBuffer[(dimY-1)/2][x];
146  continue;
147  }
148  }
149  assert(!noData||masked);
150  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
151  for(int i=-(dimX-1)/2;i<=dimX/2;++i){
152  indexI=x+i;
153  indexJ=(dimY-1)/2+j;
154  //check if out of bounds
155  if(x<(dimX-1)/2)
156  indexI=x+abs(i);
157  else if(x>=input.nrOfCol()-(dimX-1)/2)
158  indexI=x-abs(i);
159  if(y<(dimY-1)/2)
160  indexJ=(dimY-1)/2+abs(j);
161  else if(y>=input.nrOfRow()-(dimY-1)/2)
162  indexJ=(dimY-1)/2-abs(j);
163  //do not take masked values into account
164  masked=false;
165  for(int imask=0;imask<m_noDataValues.size();++imask){
166  if(inBuffer[indexJ][indexI]==m_noDataValues[imask]){
167  masked=true;
168  break;
169  }
170  }
171  if(!masked){
172  outBuffer[x]+=(m_taps[(dimY-1)/2+j][(dimX-1)/2+i]*inBuffer[indexJ][indexI]);
173  norm+=m_taps[(dimY-1)/2+j][(dimX-1)/2+i];
174  }
175  }
176  }
177  if(absolute)
178  outBuffer[x]=(normalize&&norm)? abs(outBuffer[x])/norm : abs(outBuffer[x]);
179  else if(normalize&&norm!=0)
180  outBuffer[x]=outBuffer[x]/norm;
181  }
182  //write outBuffer to file
183  try{
184  output.writeData(outBuffer,GDT_Float64,y,iband);
185  }
186  catch(std::string errorstring){
187  std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
188  }
189  progress=(1.0+y);
190  progress+=(output.nrOfRow()*iband);
191  progress/=output.nrOfBand()*output.nrOfRow();
192  pfnProgress(progress,pszMessage,pProgressArg);
193  }
194  }
195 }
196 
197 
198 void filter2d::Filter2d::majorVoting(const std::string& inputFilename, const std::string& outputFilename,int dim,const std::vector<int> &prior)
199 {
200  const char* pszMessage;
201  void* pProgressArg=NULL;
202  GDALProgressFunc pfnProgress=GDALTermProgress;
203  double progress=0;
204  pfnProgress(progress,pszMessage,pProgressArg);
205 
206  bool usePriors=true;
207  if(prior.empty()){
208  std::cout << "no prior information" << std::endl;
209  usePriors=false;
210  }
211  else{
212  std::cout << "using priors ";
213  for(int iclass=0;iclass<prior.size();++iclass)
214  std::cout << " " << static_cast<short>(prior[iclass]);
215  std::cout << std::endl;
216  }
217 
218  ImgReaderGdal input;
219  ImgWriterGdal output;
220  input.open(inputFilename);
221  output.open(outputFilename,input);
222  int dimX=0;//horizontal!!!
223  int dimY=0;//vertical!!!
224  if(dim){
225  dimX=dim;
226  dimY=dim;
227  }
228  else{
229  dimX=m_taps[0].size();
230  dimY=m_taps.size();
231  }
232 
233  assert(dimX);
234  assert(dimY);
235 
236  Vector2d<double> inBuffer(dimY,input.nrOfCol());
237  std::vector<double> outBuffer(input.nrOfCol());
238  int indexI=0;
239  int indexJ=0;
240  //initialize last half of inBuffer
241  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
242  try{
243  input.readData(inBuffer[indexJ],GDT_Float64,abs(j));
244  }
245  catch(std::string errorstring){
246  std::cerr << errorstring << "in line " << indexJ << std::endl;
247  }
248  ++indexJ;
249  }
250 
251  for(int y=0;y<input.nrOfRow();++y){
252  if(y){//inBuffer already initialized for y=0
253  //erase first line from inBuffer
254  if(dimY>1)
255  inBuffer.erase(inBuffer.begin());
256  //read extra line and push back to inBuffer if not out of bounds
257  if(y+dimY/2<input.nrOfRow()){
258  //allocate buffer
259  if(dimY>1)
260  inBuffer.push_back(inBuffer.back());
261  try{
262  input.readData(inBuffer[inBuffer.size()-1],GDT_Float64,y+dimY/2);
263  }
264  catch(std::string errorstring){
265  std::cerr << errorstring << "in line" << y << std::endl;
266  }
267  }
268  else{
269  int over=y+dimY/2-input.nrOfRow();
270  int index=(inBuffer.size()-1)-over;
271  assert(index>=0);
272  assert(index<inBuffer.size());
273  inBuffer.push_back(inBuffer[index]);
274  }
275  }
276  for(int x=0;x<input.nrOfCol();++x){
277  outBuffer[x]=0;
278  std::map<int,int> occurrence;
279  int centre=dimX*(dimY-1)/2+(dimX-1)/2;
280  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
281  for(int i=-(dimX-1)/2;i<=dimX/2;++i){
282  indexI=x+i;
283  //check if out of bounds
284  if(indexI<0)
285  indexI=-indexI;
286  else if(indexI>=input.nrOfCol())
287  indexI=input.nrOfCol()-i;
288  if(y+j<0)
289  indexJ=-j;
290  else if(y+j>=input.nrOfRow())
291  indexJ=(dimY>2) ? (dimY-1)/2-j : 0;
292  else
293  indexJ=(dimY-1)/2+j;
294 
295  // if(x<dimX/2)
296  // indexI=x+abs(i);
297  // else if(x>=input.nrOfCol()-dimX/2)
298  // indexI=x-abs(i);
299  // if(y<dimY/2)
300  // indexJ=dimY/2+abs(j);
301  // else if(y>=input.nrOfRow()-dimY/2)
302  // indexJ=dimY/2-abs(j);
303  if(usePriors){
304  occurrence[inBuffer[indexJ][indexI]]+=prior[inBuffer[indexJ][indexI]-1];
305  }
306  else
307  ++occurrence[inBuffer[indexJ][indexI]];
308  }
309  }
310  std::map<int,int>::const_iterator maxit=occurrence.begin();
311  for(std::map<int,int>::const_iterator mit=occurrence.begin();mit!=occurrence.end();++mit){
312  if(mit->second>maxit->second)
313  maxit=mit;
314  }
315  if(occurrence[inBuffer[(dimY-1)/2][x]]<maxit->second)//
316  outBuffer[x]=maxit->first;
317  else//favorize original value in case of ties
318  outBuffer[x]=inBuffer[(dimY-1)/2][x];
319  }
320  //write outBuffer to file
321  try{
322  output.writeData(outBuffer,GDT_Float64,y);
323  }
324  catch(std::string errorstring){
325  std::cerr << errorstring << "in line" << y << std::endl;
326  }
327  progress=(1.0+y)/output.nrOfRow();
328  pfnProgress(progress,pszMessage,pProgressArg);
329  }
330  input.close();
331  output.close();
332 }
333 
334 void filter2d::Filter2d::median(const std::string& inputFilename, const std::string& outputFilename,int dim, bool disc)
335 {
336  ImgReaderGdal input;
337  ImgWriterGdal output;
338  input.open(inputFilename);
339  output.open(outputFilename,input);
340  doit(input,output,"median",dim,disc);
341 }
342 
343 void filter2d::Filter2d::var(const std::string& inputFilename, const std::string& outputFilename,int dim, bool disc)
344 {
345  ImgReaderGdal input;
346  ImgWriterGdal output;
347  input.open(inputFilename);
348  output.open(outputFilename,input);
349  doit(input,output,"var",dim,disc);
350 }
351 
352 void filter2d::Filter2d::doit(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dim, short down, bool disc)
353 {
354  doit(input,output,method,dim,dim,down,disc);
355 }
356 
357 void filter2d::Filter2d::doit(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dimX, int dimY, short down, bool disc)
358 {
359  const char* pszMessage;
360  void* pProgressArg=NULL;
361  GDALProgressFunc pfnProgress=GDALTermProgress;
362  double progress=0;
363  pfnProgress(progress,pszMessage,pProgressArg);
364 
365  assert(dimX);
366  assert(dimY);
367 
369  for(int iband=0;iband<input.nrOfBand();++iband){
370  Vector2d<double> inBuffer(dimY,input.nrOfCol());
371  std::vector<double> outBuffer((input.nrOfCol()+down-1)/down);
372  int indexI=0;
373  int indexJ=0;
374  //initialize last half of inBuffer
375  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
376  try{
377  input.readData(inBuffer[indexJ],GDT_Float64,abs(j),iband);
378  }
379  catch(std::string errorstring){
380  std::cerr << errorstring << "in line " << indexJ << std::endl;
381  }
382  ++indexJ;
383  }
384  for(int y=0;y<input.nrOfRow();++y){
385  if(y){//inBuffer already initialized for y=0
386  //erase first line from inBuffer
387  if(dimY>1)
388  inBuffer.erase(inBuffer.begin());
389  //read extra line and push back to inBuffer if not out of bounds
390  if(y+dimY/2<input.nrOfRow()){
391  //allocate buffer
392  if(dimY>1)
393  inBuffer.push_back(inBuffer.back());
394  try{
395  input.readData(inBuffer[inBuffer.size()-1],GDT_Float64,y+dimY/2,iband);
396  }
397  catch(std::string errorstring){
398  std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
399  }
400  }
401  else{
402  int over=y+dimY/2-input.nrOfRow();
403  int index=(inBuffer.size()-1)-over;
404  assert(index>=0);
405  assert(index<inBuffer.size());
406  inBuffer.push_back(inBuffer[index]);
407  }
408  }
409  if((y+1+down/2)%down)
410  continue;
411  for(int x=0;x<input.nrOfCol();++x){
412  if((x+1+down/2)%down)
413  continue;
414  outBuffer[x/down]=0;
415  std::vector<double> windowBuffer;
416  std::map<long int,int> occurrence;
417  int centre=dimX*(dimY-1)/2+(dimX-1)/2;
418  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
419  for(int i=-(dimX-1)/2;i<=dimX/2;++i){
420  double d2=i*i+j*j;//square distance
421  if(disc&&(d2>(dimX/2)*(dimY/2)))
422  continue;
423  indexI=x+i;
424  //check if out of bounds
425  if(indexI<0)
426  indexI=-indexI;
427  else if(indexI>=input.nrOfCol())
428  indexI=input.nrOfCol()-i;
429  if(y+j<0)
430  indexJ=-j;
431  else if(y+j>=input.nrOfRow())
432  indexJ=(dimY>2) ? (dimY-1)/2-j : 0;
433  else
434  indexJ=(dimY-1)/2+j;
435  bool masked=false;
436  for(int imask=0;imask<m_noDataValues.size();++imask){
437  if(inBuffer[indexJ][indexI]==m_noDataValues[imask]){
438  masked=true;
439  break;
440  }
441  }
442  if(!masked){
443  std::vector<short>::const_iterator vit=m_class.begin();
444  if(!m_class.size())
445  ++occurrence[inBuffer[indexJ][indexI]];
446  else{
447  while(vit!=m_class.end()){
448  if(inBuffer[indexJ][indexI]==*(vit++))
449  ++occurrence[inBuffer[indexJ][indexI]];
450  }
451  }
452  windowBuffer.push_back(inBuffer[indexJ][indexI]);
453  }
454  }
455  }
456  switch(getFilterType(method)){
457  case(filter2d::median):
458  if(windowBuffer.empty())
459  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
460  else
461  outBuffer[x/down]=stat.median(windowBuffer);
462  break;
463  case(filter2d::var):{
464  if(windowBuffer.empty())
465  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
466  else
467  outBuffer[x/down]=stat.var(windowBuffer);
468  break;
469  }
470  case(filter2d::stdev):{
471  if(windowBuffer.empty())
472  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
473  else
474  outBuffer[x/down]=sqrt(stat.var(windowBuffer));
475  break;
476  }
477  case(filter2d::mean):{
478  if(windowBuffer.empty())
479  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
480  else
481  outBuffer[x/down]=stat.mean(windowBuffer);
482  break;
483  }
484  case(filter2d::min):{
485  if(windowBuffer.empty())
486  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
487  else
488  outBuffer[x/down]=stat.mymin(windowBuffer);
489  break;
490  }
491  case(filter2d::ismin):{
492  if(windowBuffer.empty())
493  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
494  else
495  outBuffer[x/down]=(stat.mymin(windowBuffer)==windowBuffer[centre])? 1:0;
496  break;
497  }
498  case(filter2d::minmax):{//is the same as homog?
499  double min=0;
500  double max=0;
501  if(windowBuffer.empty())
502  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
503  else{
504  stat.minmax(windowBuffer,windowBuffer.begin(),windowBuffer.end(),min,max);
505  if(min!=max)
506  outBuffer[x/down]=0;
507  else
508  outBuffer[x/down]=windowBuffer[centre];//centre pixels
509  }
510  break;
511  }
512  case(filter2d::max):{
513  if(windowBuffer.empty())
514  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
515  else
516  outBuffer[x/down]=stat.mymax(windowBuffer);
517  break;
518  }
519  case(filter2d::ismax):{
520  if(windowBuffer.empty())
521  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
522  else
523  outBuffer[x/down]=(stat.mymax(windowBuffer)==windowBuffer[centre])? 1:0;
524  break;
525  }
526  case(filter2d::order):{
527  if(windowBuffer.empty())
528  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
529  else{
530  double lbound=0;
531  double ubound=dimX*dimY;
532  double theMin=stat.mymin(windowBuffer);
533  double theMax=stat.mymax(windowBuffer);
534  double scale=(ubound-lbound)/(theMax-theMin);
535  outBuffer[x/down]=static_cast<short>(scale*(windowBuffer[centre]-theMin)+lbound);
536  }
537  break;
538  }
539  case(filter2d::sum):{
540  outBuffer[x/down]=stat.sum(windowBuffer);
541  break;
542  }
543  case(filter2d::percentile):{
544  assert(m_threshold.size());
545  outBuffer[x/down]=stat.percentile(windowBuffer,windowBuffer.begin(),windowBuffer.end(),m_threshold[0]);
546  break;
547  }
548  case(filter2d::proportion):{
549  if(windowBuffer.size()){
550  double sum=stat.sum(windowBuffer);
551  if(sum)
552  outBuffer[x/down]=100.0*windowBuffer[centre]/stat.sum(windowBuffer);
553  else
554  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
555  }
556  else
557  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
558  break;
559  }
560  case(filter2d::homog):
561  if(occurrence.size()==1)//all values in window are the same
562  outBuffer[x/down]=inBuffer[(dimY-1)/2][x];
563  else
564  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
565  break;
566  case(filter2d::heterog):{
567  if(occurrence.size()==windowBuffer.size())
568  outBuffer[x/down]=inBuffer[(dimY-1)/2][x];
569  else
570  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
571  // if(occurrence.size()==1)//all values in window are the same
572  // outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
573  // else
574  // outBuffer[x/down]=inBuffer[(dimY-1)/2][x];
575  // break;
576  // for(std::vector<double>::const_iterator wit=windowBuffer.begin();wit!=windowBuffer.end();++wit){
577  // if(wit==windowBuffer.begin()+windowBuffer.size()/2)
578  // continue;
579  // else if(*wit!=inBuffer[(dimY-1)/2][x]){
580  // outBuffer[x/down]=1;
581  // break;
582  // }
583  // else if(*wit==inBuffer[(dimY-1)/2][x]){//todo:wit mag niet central pixel zijn
584  // outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
585  // break;
586  // }
587  // }
588  // break;
589  }
590  case(filter2d::density):{
591  if(windowBuffer.size()){
592  std::vector<short>::const_iterator vit=m_class.begin();
593  while(vit!=m_class.end())
594  outBuffer[x/down]+=100.0*occurrence[*(vit++)]/windowBuffer.size();
595  }
596  else
597  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
598  break;
599  }
600  case(filter2d::countid):{
601  if(windowBuffer.size())
602  outBuffer[x/down]=occurrence.size();
603  else
604  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
605  break;
606  }
607  case(filter2d::mode):{
608  if(occurrence.size()){
609  std::map<long int,int>::const_iterator maxit=occurrence.begin();
610  for(std::map<long int,int>::const_iterator mit=occurrence.begin();mit!=occurrence.end();++mit){
611  if(mit->second>maxit->second)
612  maxit=mit;
613  }
614  if(occurrence[inBuffer[(dimY-1)/2][x]]<maxit->second)//
615  outBuffer[x/down]=maxit->first;
616  else//favorize original value in case of ties
617  outBuffer[x/down]=inBuffer[(dimY-1)/2][x];
618  }
619  else
620  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
621  break;
622  }
623  case(filter2d::threshold):{
624  assert(m_class.size()==m_threshold.size());
625  if(windowBuffer.size()){
626  outBuffer[x/down]=inBuffer[(dimY-1)/2][x];//initialize with original value (in case thresholds not met)
627  for(int iclass=0;iclass<m_class.size();++iclass){
628  if(100.0*(occurrence[m_class[iclass]])/windowBuffer.size()>m_threshold[iclass])
629  outBuffer[x/down]=m_class[iclass];
630  }
631  }
632  else
633  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
634  break;
635  }
636  case(filter2d::scramble):{//could be done more efficiently window by window with random shuffling entire buffer and assigning entire buffer at once to output image...
637  if(windowBuffer.size()){
638  int randomIndex=std::rand()%windowBuffer.size();
639  if(randomIndex>=windowBuffer.size())
640  outBuffer[x/down]=windowBuffer.back();
641  else if(randomIndex<0)
642  outBuffer[x/down]=windowBuffer[0];
643  else
644  outBuffer[x/down]=windowBuffer[randomIndex];
645  }
646  else
647  outBuffer[x/down]=(m_noDataValues.size())? m_noDataValues[0] : 0;
648  break;
649  }
650  case(filter2d::mixed):{
651  enum Type { BF=11, CF=12, MF=13, NF=20, W=30 };
652  double nBF=occurrence[BF];
653  double nCF=occurrence[CF];
654  double nMF=occurrence[MF];
655  double nNF=occurrence[NF];
656  double nW=occurrence[W];
657  if(windowBuffer.size()){
658  if((nBF+nCF+nMF)&&(nBF+nCF+nMF>=nNF+nW)){//forest
659  if(nBF/(nBF+nCF)>=0.75)
660  outBuffer[x/down]=BF;
661  else if(nCF/(nBF+nCF)>=0.75)
662  outBuffer[x/down]=CF;
663  else
664  outBuffer[x/down]=MF;
665  }
666  else{//non-forest
667  if(nW&&(nW>=nNF))
668  outBuffer[x/down]=W;
669  else
670  outBuffer[x/down]=NF;
671  }
672  }
673  else
674  outBuffer[x/down]=inBuffer[indexJ][indexI];
675  break;
676  }
677  default:{
678  std::ostringstream ess;
679  ess << "Error: filter method " << method << " not supported" << std::endl;
680  throw(ess.str());
681  break;
682  }
683  }
684  }
685  progress=(1.0+y/down);
686  progress+=(output.nrOfRow()*iband);
687  progress/=output.nrOfBand()*output.nrOfRow();
688  pfnProgress(progress,pszMessage,pProgressArg);
689  //write outBuffer to file
690  try{
691  output.writeData(outBuffer,GDT_Float64,y/down,iband);
692  }
693  catch(std::string errorstring){
694  std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
695  }
696  }
697  }
698  pfnProgress(1.0,pszMessage,pProgressArg);
699 }
700 
701 void filter2d::Filter2d::mrf(const ImgReaderGdal& input, ImgWriterGdal& output, int dimX, int dimY, double beta, bool eightConnectivity, short down, bool verbose){
702  assert(m_class.size()>1);
703  Vector2d<double> fullBeta(m_class.size(),m_class.size());
704  for(int iclass1=0;iclass1<m_class.size();++iclass1)
705  for(int iclass2=0;iclass2<m_class.size();++iclass2)
706  fullBeta[iclass1][iclass2]=beta;
707  mrf(input,output,dimX,dimY,fullBeta,eightConnectivity,down,verbose);
708 }
709 
710 //beta[classTo][classFrom]
711 void filter2d::Filter2d::mrf(const ImgReaderGdal& input, ImgWriterGdal& output, int dimX, int dimY, Vector2d<double> beta, bool eightConnectivity, short down, bool verbose)
712 {
713  const char* pszMessage;
714  void* pProgressArg=NULL;
715  GDALProgressFunc pfnProgress=GDALTermProgress;
716  double progress=0;
717  pfnProgress(progress,pszMessage,pProgressArg);
718 
719  assert(dimX);
720  assert(dimY);
721 
722  Vector2d<short> inBuffer(dimY,input.nrOfCol());
723  Vector2d<double> outBuffer(m_class.size(),(input.nrOfCol()+down-1)/down);
724  assert(input.nrOfBand()==1);
725  assert(output.nrOfBand()==m_class.size());
726  assert(m_class.size()>1);
727  assert(beta.size()==m_class.size());
728  int indexI=0;
729  int indexJ=0;
730  //initialize last half of inBuffer
731  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
732  try{
733  input.readData(inBuffer[indexJ],GDT_Int16,abs(j));
734  }
735  catch(std::string errorstring){
736  std::cerr << errorstring << "in line " << indexJ << std::endl;
737  }
738  ++indexJ;
739  }
740  for(int y=0;y<input.nrOfRow();++y){
741  if(y){//inBuffer already initialized for y=0
742  //erase first line from inBuffer
743  if(dimY>1)
744  inBuffer.erase(inBuffer.begin());
745  //read extra line and push back to inBuffer if not out of bounds
746  if(y+dimY/2<input.nrOfRow()){
747  //allocate buffer
748  if(dimY>1)
749  inBuffer.push_back(inBuffer.back());
750  try{
751  input.readData(inBuffer[inBuffer.size()-1],GDT_Int16,y+dimY/2);
752  }
753  catch(std::string errorstring){
754  std::cerr << errorstring << "in line " << y << std::endl;
755  }
756  }
757  else{
758  int over=y+dimY/2-input.nrOfRow();
759  int index=(inBuffer.size()-1)-over;
760  assert(index>=0);
761  assert(index<inBuffer.size());
762  inBuffer.push_back(inBuffer[index]);
763  }
764  }
765  if((y+1+down/2)%down)
766  continue;
767  for(int x=0;x<input.nrOfCol();++x){
768  if((x+1+down/2)%down)
769  continue;
770  std::vector<short> potential(m_class.size());
771  for(int iclass=0;iclass<m_class.size();++iclass){
772  potential[iclass]=0;
773  outBuffer[iclass][x/down]=0;
774  }
775  std::vector<double> windowBuffer;
776  int centre=dimX*(dimY-1)/2+(dimX-1)/2;
777  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
778  for(int i=-(dimX-1)/2;i<=dimX/2;++i){
779  if(i!=0&&j!=0&&!eightConnectivity)
780  continue;
781  if(i==0&&j==0)
782  continue;
783  indexI=x+i;
784  //check if out of bounds
785  if(indexI<0)
786  indexI=-indexI;
787  else if(indexI>=input.nrOfCol())
788  indexI=input.nrOfCol()-i;
789  if(y+j<0)
790  indexJ=-j;
791  else if(y+j>=input.nrOfRow())
792  indexJ=(dimY>2) ? (dimY-1)/2-j : 0;
793  else
794  indexJ=(dimY-1)/2+j;
795  bool masked=false;
796  for(int imask=0;imask<m_noDataValues.size();++imask){
797  if(inBuffer[indexJ][indexI]==m_noDataValues[imask]){
798  masked=true;
799  break;
800  }
801  }
802  if(!masked){
803  for(int iclass=0;iclass<m_class.size();++iclass){
804  if(inBuffer[indexJ][indexI]==m_class[iclass])
805  potential[iclass]+=1;
806  }
807  }
808  }
809  }
810  double norm=0;
811  for(int iclass1=0;iclass1<m_class.size();++iclass1){
812  assert(beta[iclass1].size()==m_class.size());
813  double pot=0;
814  for(int iclass2=0;iclass2<m_class.size();++iclass2)
815  if(iclass2!=iclass1)
816  pot+=potential[iclass2]*beta[iclass1][iclass2];
817  double prior=exp(-pot);
818  outBuffer[iclass1][x/down]=prior;
819  norm+=prior;
820  }
821  if(norm){
822  for(int iclass1=0;iclass1<m_class.size();++iclass1)
823  outBuffer[iclass1][x/down]/=norm;
824  }
825  }
826  progress=(1.0+y/down)/output.nrOfRow();
827  pfnProgress(progress,pszMessage,pProgressArg);
828  //write outBuffer to file
829  assert(outBuffer.size()==m_class.size());
830  assert(y<output.nrOfRow());
831  for(int iclass=0;iclass<m_class.size();++iclass){
832  assert(outBuffer[iclass].size()==output.nrOfCol());
833  try{
834  output.writeData(outBuffer[iclass],GDT_Float64,y/down,iclass);
835  }
836  catch(std::string errorstring){
837  std::cerr << errorstring << "in class " << iclass << ", line " << y << std::endl;
838  }
839  }
840  }
841 }
842 
843 void filter2d::Filter2d::shift(const ImgReaderGdal& input, ImgWriterGdal& output, double offsetX, double offsetY, double randomSigma, RESAMPLE resample, bool verbose)
844 {
845  assert(input.nrOfCol()==output.nrOfCol());
846  assert(input.nrOfRow()==output.nrOfRow());
847  assert(input.nrOfBand()==output.nrOfBand());
848  const char* pszMessage;
849  void* pProgressArg=NULL;
850  GDALProgressFunc pfnProgress=GDALTermProgress;
851  double progress=0;
852  pfnProgress(progress,pszMessage,pProgressArg);
853  //process band per band in memory
854  Vector2d<double> inBuffer(input.nrOfRow(),output.nrOfCol());
855  Vector2d<double> outBuffer(input.nrOfRow(),output.nrOfCol());
856  for(int iband=0;iband<input.nrOfBand();++iband){
857  input.readDataBlock(inBuffer,GDT_Float64,0,inBuffer.nCols()-1,0,inBuffer.nRows()-1,iband);
858  shift(inBuffer,outBuffer,offsetX,offsetY,randomSigma,resample,verbose);
859  output.writeDataBlock(outBuffer,GDT_Float64,0,outBuffer.nCols()-1,0,outBuffer.nRows()-1,iband);
860  }
861 }
862 
863 //todo: re-implement without dependency of CImg and reg libraries
864 // void filter2d::Filter2d::dwt_texture(const std::string& inputFilename, const std::string& outputFilename,int dim, int scale, int down, int iband, bool verbose)
865 // {
866 // ImgReaderGdal input;
867 // ImgWriterGdal output;
868 // if(verbose)
869 // std::cout << "opening file " << inputFilename << std::endl;
870 // input.open(inputFilename);
871 // double magicX=1,magicY=1;
872 // output.open(outputFilename,(input.nrOfCol()+down-1)/down,(input.nrOfRow()+down-1)/down,scale*3,GDT_Float32,input.getImageType());
873 // if(input.isGeoRef()){
874 // output.setProjection(input.getProjection());
875 // output.copyGeoTransform(input);
876 // }
877 // if(verbose)
878 // std::cout << "Dimension texture (row x col x band) = " << (input.nrOfCol()+down-1)/down << " x " << (input.nrOfRow()+down-1)/down << " x " << scale*3 << std::endl;
879 // assert(dim%2);
880 // int dimX=dim;
881 // int dimY=dim;
882 // Vector2d<float> inBuffer(dimY,input.nrOfCol());
883 // Vector2d<float> outBuffer(scale*3,(input.nrOfCol()+down-1)/down);
884 // //initialize last half of inBuffer
885 // int indexI=0;
886 // int indexJ=0;
887 // for(int j=-dimY/2;j<(dimY+1)/2;++j){
888 // try{
889 // if(verbose)
890 // cout << "reading input line " << abs(j) << std::endl;
891 // input.readData(inBuffer[indexJ],GDT_Float32,abs(j),iband);
892 // ++indexJ;
893 // }
894 // catch(std::string errorstring){
895 // std::cerr << errorstring << "in band " << iband << ", line " << indexJ << std::endl;
896 // }
897 // }
898 // const char* pszMessage;
899 // void* pProgressArg=NULL;
900 // GDALProgressFunc pfnProgress=GDALTermProgress;
901 // double progress=0;
902 // pfnProgress(progress,pszMessage,pProgressArg);
903 // for(int y=0;y<input.nrOfRow();y+=down){
904 // if(verbose)
905 // std::cout << "calculating line " << y/down << std::endl;
906 // if(y){//inBuffer already initialized for y=0
907 // //erase first line from inBuffer
908 // inBuffer.erase(inBuffer.begin());
909 // //read extra line and push back to inBuffer if not out of bounds
910 // if(y+dimY/2<input.nrOfRow()){
911 // //allocate buffer
912 // inBuffer.push_back(inBuffer.back());
913 // try{
914 // if(verbose)
915 // std::cout << "reading input line " << y+dimY/2 << std::endl;
916 // input.readData(inBuffer[inBuffer.size()-1],GDT_Float32,y+dimY/2,iband);
917 // }
918 // catch(std::string errorstring){
919 // std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
920 // }
921 // }
922 // }
923 // for(int x=0;x<input.nrOfCol();x+=down){
924 // Vector2d<double> texture_feature(scale,3);
925 // CImg<> texture_in(dimX,dimY);
926 // int r=0;//index for row of texture_in
927 // for(int j=-dimY/2;j<(dimY+1)/2;++j){
928 // int c=0;
929 // for(int i=-dimX/2;i<(dimX+1)/2;++i){
930 // indexI=x+i;
931 // //check if out of bounds
932 // if(indexI<0)
933 // indexI=-indexI;
934 // else if(indexI>=input.nrOfCol())
935 // indexI=input.nrOfCol()-i;
936 // if(y+j<0)
937 // indexJ=-j;
938 // else if(y+j>=input.nrOfRow())
939 // indexJ=dimY/2-j;//indexJ=inBuffer.size()-1-j;
940 // else
941 // indexJ=dimY/2+j;
942 // assert(indexJ<inBuffer.size());
943 // assert(indexI<inBuffer[indexJ].size());
944 // texture_in(r,c)=inBuffer[indexJ][indexI];
945 // c++;
946 // }
947 // ++r;
948 // }
949 // texture_in.dwt_texture(texture_feature,scale);
950 // for(int v=0;v<scale*3;++v)
951 // outBuffer[v][x/down]=texture_feature[v/3][v%3];
952 // }
953 // //write outBuffer to file
954 // try{
955 // if(verbose)
956 // std::cout << "writing line " << y/down << std::endl;
957 // for(int v=0;v<scale*3;++v)
958 // output.writeData(outBuffer[v],GDT_Float32,y/down,v);
959 // }
960 // catch(std::string errorstring){
961 // std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
962 // }
963 // progress=(1.0+y)/output.nrOfRow();
964 // pfnProgress(progress,pszMessage,pProgressArg);
965 // }
966 // input.close();
967 // output.close();
968 // }
969 
970 void filter2d::Filter2d::morphology(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& method, int dimX, int dimY, const std::vector<double> &angle, bool disc)
971 {
972  const char* pszMessage;
973  void* pProgressArg=NULL;
974  GDALProgressFunc pfnProgress=GDALTermProgress;
975  double progress=0;
976  pfnProgress(progress,pszMessage,pProgressArg);
977 
978  assert(dimX);
979  assert(dimY);
980 
982  for(int iband=0;iband<input.nrOfBand();++iband){
983  Vector2d<double> inBuffer(dimY,input.nrOfCol());
984  std::vector<double> outBuffer(input.nrOfCol());
985  int indexI=0;
986  int indexJ=0;
987  //initialize last half of inBuffer
988  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
989  try{
990  input.readData(inBuffer[indexJ],GDT_Float64,abs(j),iband);
991  ++indexJ;
992  }
993  catch(std::string errorstring){
994  std::cerr << errorstring << "in line " << indexJ << std::endl;
995  }
996  }
997  for(int y=0;y<input.nrOfRow();++y){
998  if(y){//inBuffer already initialized for y=0
999  //erase first line from inBuffer
1000  if(dimY>1)
1001  inBuffer.erase(inBuffer.begin());
1002  //read extra line and push back to inBuffer if not out of bounds
1003  if(y+dimY/2<input.nrOfRow()){
1004  //allocate buffer
1005  if(dimY>1)
1006  inBuffer.push_back(inBuffer.back());
1007  try{
1008  input.readData(inBuffer[inBuffer.size()-1],GDT_Float64,y+dimY/2,iband);
1009  }
1010  catch(std::string errorstring){
1011  std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
1012  }
1013  }
1014  else{
1015  int over=y+dimY/2-input.nrOfRow();
1016  int index=(inBuffer.size()-1)-over;
1017  assert(index>=0);
1018  assert(index<inBuffer.size());
1019  inBuffer.push_back(inBuffer[index]);
1020  }
1021  }
1022  for(int x=0;x<input.nrOfCol();++x){
1023  double currentValue=inBuffer[(dimY-1)/2][x];
1024  outBuffer[x]=currentValue;
1025  std::vector<double> statBuffer;
1026  bool currentMasked=false;
1027  int centre=dimX*(dimY-1)/2+(dimX-1)/2;
1028  for(int imask=0;imask<m_noDataValues.size();++imask){
1029  if(currentValue==m_noDataValues[imask]){
1030  currentMasked=true;
1031  break;
1032  }
1033  }
1034  if(currentMasked){
1035  outBuffer[x]=currentValue;
1036  }
1037  else{
1038  for(int j=-(dimY-1)/2;j<=dimY/2;++j){
1039  for(int i=-(dimX-1)/2;i<=dimX/2;++i){
1040  double d2=i*i+j*j;//square distance
1041  if(disc&&(d2>(dimX/2)*(dimY/2)))
1042  continue;
1043  if(angle.size()){
1044  double theta;
1045  //use polar coordinates in radians
1046  if(i>0){
1047  if(j<0)
1048  theta=atan(static_cast<double>(-j)/(static_cast<double>(i)));
1049  else
1050  theta=-atan(static_cast<double>(j)/(static_cast<double>(i)));
1051  }
1052  else if(i<0){
1053  if(j<0)
1054  theta=PI-atan(static_cast<double>(-j)/(static_cast<double>(-i)));
1055  else
1056  theta=PI+atan(static_cast<double>(j)/(static_cast<double>(-i)));
1057  }
1058  else if(j<0)
1059  theta=PI/2.0;
1060  else if(j>0)
1061  theta=3.0*PI/2.0;
1062  //convert to North (0), East (90), South (180), West (270) in degrees
1063  theta=360-(theta/PI*180)+90;
1064  if(theta<0)
1065  theta+=360;
1066  while(theta>360)
1067  theta-=360;
1068  bool alligned=false;
1069  for(int iangle=0;iangle<angle.size();++iangle){
1070  if(sqrt((theta-angle[iangle])*(theta-angle[iangle]))<10){
1071  alligned=true;
1072  break;
1073  }
1074  }
1075  if(!alligned)
1076  continue;
1077  }
1078  indexI=x+i;
1079  //check if out of bounds
1080  if(indexI<0)
1081  indexI=-indexI;
1082  else if(indexI>=input.nrOfCol())
1083  indexI=input.nrOfCol()-i;
1084  if(y+j<0)
1085  indexJ=-j;
1086  else if(y+j>=input.nrOfRow())
1087  indexJ=(dimY>2) ? (dimY-1)/2-j : 0;
1088  else
1089  indexJ=(dimY-1)/2+j;
1090  //todo: introduce novalue as this: ?
1091  // if(inBuffer[indexJ][indexI]==(m_noDataValues.size())? m_noDataValues[0] : 0)
1092  // continue;
1093  bool masked=false;
1094  for(int imask=0;imask<m_noDataValues.size();++imask){
1095  if(inBuffer[indexJ][indexI]==m_noDataValues[imask]){
1096  masked=true;
1097  break;
1098  }
1099  }
1100  if(!masked){
1101  short binValue=0;
1102  for(int iclass=0;iclass<m_class.size();++iclass){
1103  if(inBuffer[indexJ][indexI]==m_class[iclass]){
1104  binValue=1;
1105  break;
1106  }
1107  }
1108  if(m_class.size())
1109  statBuffer.push_back(binValue);
1110  else
1111  statBuffer.push_back(inBuffer[indexJ][indexI]);
1112  }
1113  }
1114  }
1115  if(statBuffer.size()){
1116  switch(getFilterType(method)){
1117  case(filter2d::dilate):
1118  outBuffer[x]=stat.mymax(statBuffer);
1119  break;
1120  case(filter2d::erode):
1121  outBuffer[x]=stat.mymin(statBuffer);
1122  break;
1123  default:
1124  std::ostringstream ess;
1125  ess << "Error: morphology method " << method << " not supported, choose " << filter2d::dilate << " (dilate) or " << filter2d::erode << " (erode)" << std::endl;
1126  throw(ess.str());
1127  break;
1128  }
1129  }
1130  if(outBuffer[x]&&m_class.size())
1131  outBuffer[x]=m_class[0];
1132  }
1133  }
1134  //write outBuffer to file
1135  try{
1136  output.writeData(outBuffer,GDT_Float64,y,iband);
1137  }
1138  catch(std::string errorstring){
1139  std::cerr << errorstring << "in band " << iband << ", line " << y << std::endl;
1140  }
1141  progress=(1.0+y);
1142  progress+=(output.nrOfRow()*iband);
1143  progress/=output.nrOfBand()*output.nrOfRow();
1144  pfnProgress(progress,pszMessage,pProgressArg);
1145  }
1146  }
1147 }
1148 
1149 void filter2d::Filter2d::shadowDsm(const ImgReaderGdal& input, ImgWriterGdal& output, double sza, double saa, double pixelSize, short shadowFlag){
1150  Vector2d<float> inputBuffer;
1151  Vector2d<float> outputBuffer;
1152  input.readDataBlock(inputBuffer, GDT_Float32, 0, input.nrOfCol()-1, 0, input.nrOfRow()-1, 0);
1153  shadowDsm(inputBuffer, outputBuffer, sza, saa, pixelSize, shadowFlag);
1154  output.writeDataBlock(outputBuffer,GDT_Float32,0,output.nrOfCol()-1,0,output.nrOfRow()-1,0);
1155 }
1156 
1157 void filter2d::Filter2d::dwtForward(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& wavelet_type, int family){
1158  Vector2d<float> theBuffer;
1159  for(int iband=0;iband<input.nrOfBand();++iband){
1160  input.readDataBlock(theBuffer, GDT_Float32, 0, input.nrOfCol()-1, 0, input.nrOfRow()-1, iband);
1161  std::cout << "filtering band " << iband << std::endl << std::flush;
1162  dwtForward(theBuffer, wavelet_type, family);
1163  output.writeDataBlock(theBuffer,GDT_Float32,0,output.nrOfCol()-1,0,output.nrOfRow()-1,iband);
1164  }
1165 }
1166 
1167 void filter2d::Filter2d::dwtInverse(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& wavelet_type, int family){
1168  Vector2d<float> theBuffer;
1169  for(int iband=0;iband<input.nrOfBand();++iband){
1170  input.readDataBlock(theBuffer, GDT_Float32, 0, input.nrOfCol()-1, 0, input.nrOfRow()-1, iband);
1171  std::cout << "filtering band " << iband << std::endl << std::flush;
1172  dwtInverse(theBuffer, wavelet_type, family);
1173  output.writeDataBlock(theBuffer,GDT_Float32,0,output.nrOfCol()-1,0,output.nrOfRow()-1,iband);
1174  }
1175 }
1176 
1177 void filter2d::Filter2d::dwtCut(const ImgReaderGdal& input, ImgWriterGdal& output, const std::string& wavelet_type, int family, double cut, bool verbose){
1178  Vector2d<float> theBuffer;
1179  for(int iband=0;iband<input.nrOfBand();++iband){
1180  input.readDataBlock(theBuffer, GDT_Float32, 0, input.nrOfCol()-1, 0, input.nrOfRow()-1, iband);
1181  std::cout << "filtering band " << iband << std::endl << std::flush;
1182  dwtCut(theBuffer, wavelet_type, family, cut);
1183  output.writeDataBlock(theBuffer,GDT_Float32,0,output.nrOfCol()-1,0,output.nrOfRow()-1,iband);
1184  }
1185 }
1186 
1187 void filter2d::Filter2d::linearFeature(const ImgReaderGdal& input, ImgWriterGdal& output, float angle, float angleStep, float maxDistance, float eps, bool l1, bool a1, bool l2, bool a2, int band, bool verbose){
1188  Vector2d<float> inputBuffer;
1189  std::vector< Vector2d<float> > outputBuffer;
1190  input.readDataBlock(inputBuffer, GDT_Float32, 0, input.nrOfCol()-1, 0, input.nrOfRow()-1, band);
1191  if(maxDistance<=0)
1192  maxDistance=sqrt(static_cast<float>(input.nrOfCol()*input.nrOfRow()));
1193  linearFeature(inputBuffer,outputBuffer,angle,angleStep,maxDistance,eps, l1, a1, l2, a2,verbose);
1194  for(int iband=0;iband<outputBuffer.size();++iband)
1195  output.writeDataBlock(outputBuffer[iband],GDT_Float32,0,output.nrOfCol()-1,0,output.nrOfRow()-1,iband);
1196 }
1197 
1198 void filter2d::Filter2d::linearFeature(const Vector2d<float>& input, std::vector< Vector2d<float> >& output, float angle, float angleStep, float maxDistance, float eps, bool l1, bool a1, bool l2, bool a2, bool verbose)
1199 {
1200  output.clear();
1201  int nband=0;//linear feature
1202  if(l1)
1203  ++nband;
1204  if(a1)
1205  ++nband;
1206  if(l2)
1207  ++nband;
1208  if(a2)
1209  ++nband;
1210  output.resize(nband);
1211  for(int iband=0;iband<output.size();++iband)
1212  output[iband].resize(input.nRows(),input.nCols());
1213  if(maxDistance<=0)
1214  maxDistance=sqrt(static_cast<float>(input.nRows()*input.nCols()));
1215  int indexI=0;
1216  int indexJ=0;
1217  const char* pszMessage;
1218  void* pProgressArg=NULL;
1219  GDALProgressFunc pfnProgress=GDALTermProgress;
1220  double progress=0;
1221  pfnProgress(progress,pszMessage,pProgressArg);
1222  for(int y=0;y<input.nRows();++y){
1223  for(int x=0;x<input.nCols();++x){
1224  float currentValue=input[y][x];
1225  //find values equal to current value with some error margin
1226  //todo: add distance for two opposite directions
1227  float lineDistance1=0;//longest line of object
1228  float lineDistance2=maxDistance;//shortest line of object
1229  float lineAngle1=0;//angle to longest line (North=0)
1230  float lineAngle2=0;//angle to shortest line (North=0)
1231  float northAngle=0;//rotating angle
1232  for(northAngle=0;northAngle<180;northAngle+=angleStep){
1233  if(angle<=360&&angle>=0&&angle!=northAngle)
1234  continue;
1235  //test
1236  if(verbose)
1237  std::cout << "northAngle: " << northAngle << std::endl;
1238  float currentDistance=0;
1239  float theDir=0;
1240  for(short side=0;side<=1;side+=1){
1241  theDir=PI/2.0-DEG2RAD(northAngle)+side*PI;//in radians
1242  //test
1243  if(verbose)
1244  std::cout << "theDir in deg: " << RAD2DEG(theDir) << std::endl;
1245  if(theDir<0)
1246  theDir+=2*PI;
1247  //test
1248  if(verbose)
1249  std::cout << "theDir in deg: " << RAD2DEG(theDir) << std::endl;
1250  float nextValue=currentValue;
1251  for(float currentRay=1;currentRay<maxDistance;++currentRay){
1252  indexI=x+currentRay*cos(theDir);
1253  indexJ=y-currentRay*sin(theDir);
1254  if(indexJ<0||indexJ>=input.size())
1255  break;
1256  if(indexI<0||indexI>=input[indexJ].size())
1257  break;
1258  nextValue=input[indexJ][indexI];
1259  if(verbose){
1260  std::cout << "x: " << x << std::endl;
1261  std::cout << "y: " << y << std::endl;
1262  std::cout << "currentValue: " << currentValue << std::endl;
1263  std::cout << "theDir in degrees: " << RAD2DEG(theDir) << std::endl;
1264  std::cout << "cos(theDir): " << cos(theDir) << std::endl;
1265  std::cout << "sin(theDir): " << sin(theDir) << std::endl;
1266  std::cout << "currentRay: " << currentRay << std::endl;
1267  std::cout << "currentDistance: " << currentDistance << std::endl;
1268  std::cout << "indexI: " << indexI << std::endl;
1269  std::cout << "indexJ: " << indexJ << std::endl;
1270  std::cout << "nextValue: " << nextValue << std::endl;
1271  }
1272  if(fabs(currentValue-nextValue)<=eps){
1273  ++currentDistance;
1274  //test
1275  if(verbose)
1276  std::cout << "currentDistance: " << currentDistance << ", continue" << std::endl;
1277  }
1278  else{
1279  if(verbose)
1280  std::cout << "currentDistance: " << currentDistance << ", break" << std::endl;
1281  break;
1282  }
1283  }
1284  }
1285  if(lineDistance1<currentDistance){
1286  lineDistance1=currentDistance;
1287  lineAngle1=northAngle;
1288  }
1289  if(lineDistance2>currentDistance){
1290  lineDistance2=currentDistance;
1291  lineAngle2=northAngle;
1292  }
1293  if(verbose){
1294  std::cout << "lineDistance1: " << lineDistance1 << std::endl;
1295  std::cout << "lineAngle1: " << lineAngle1 << std::endl;
1296  std::cout << "lineDistance2: " << lineDistance2 << std::endl;
1297  std::cout << "lineAngle2: " << lineAngle2 << std::endl;
1298  }
1299  }
1300  int iband=0;
1301  if(l1)
1302  output[iband++][y][x]=lineDistance1;
1303  if(a1)
1304  output[iband++][y][x]=lineAngle1;
1305  if(l2)
1306  output[iband++][y][x]=lineDistance2;
1307  if(a2)
1308  output[iband++][y][x]=lineAngle2;
1309  assert(iband==nband);
1310  }
1311  progress=(1.0+y);
1312  progress/=input.nRows();
1313  pfnProgress(progress,pszMessage,pProgressArg);
1314  }
1315 }
Definition: Filter.h:33