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