source: trunk/src/GenericEdgeDetector.cpp @ 3041

Last change on this file since 3041 was 3041, checked in by Takeshi Nakazato, 9 years ago

New Development: No

JIRA Issue: Yes CAS-7743

Ready for Test: Yes

Interface Changes: Yes/No?

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...


Better handling of large number that exceeds a limit of uInt (unsigned int) and proper handling of possible memory allocation error.

File size: 12.8 KB
Line 
1//
2// C++ Implimentation: GenericEdgeDetector
3//
4// Description:
5//
6//
7// Author: Takeshi Nakazato <takeshi.nakazato@nao.ac.jp>, (C) 2012
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12#include <math.h>
13#include <limits.h>
14#include <stdint.h>
15
16#include <casa/Arrays/Vector.h>
17#include <casa/Arrays/Matrix.h>
18#include <casa/Arrays/ArrayMath.h>
19#include <casa/Arrays/ArrayIO.h>
20#include <casa/Utilities/GenSort.h>
21
22#include <coordinates/Coordinates/DirectionCoordinate.h>
23
24#include "GenericEdgeDetector.h"
25
26using namespace std ;
27using namespace casa ;
28
29namespace asap {
30
31GenericEdgeDetector::GenericEdgeDetector()
32  : EdgeDetector()
33{}
34
35GenericEdgeDetector::~GenericEdgeDetector()
36{}
37
38Vector<uInt> GenericEdgeDetector::detect()
39{
40  os_.origin(LogOrigin( "GenericEdgeDetector", "detect", WHERE )) ;
41
42  initDetect() ;
43
44  topixel() ;
45  countup() ;
46  thresholding() ;
47  labeling() ;
48  trimming() ;
49  selection() ;
50  tuning() ;
51
52  os_ << LogIO::DEBUGGING
53      << "Detected " << off_.nelements() << " integrations as OFF" << LogIO::POST ; 
54
55  return off_ ;
56}
57
58void GenericEdgeDetector::parseOption( const Record &option )
59{
60  os_.origin(LogOrigin( "GenericEdgeDetector", "parseOption", WHERE )) ;
61
62  String name = "fraction" ;
63  if ( option.isDefined( name ) ) {
64    if ( option.dataType( name ) == TpString ) {
65      // should be "xx%" format
66      String fstr = option.asString( name ) ;
67      fstr = fstr.substr(0,fstr.size()-1) ;
68      fraction_ = String::toFloat( fstr ) * 0.01 ;
69    }
70    else {
71      fraction_ = option.asFloat( name ) ;
72    }
73  }
74  else {
75    fraction_ = 0.1 ; // default is 10%
76  }
77 
78  name = "width" ;
79  if ( option.isDefined( name ) ) {
80    width_ = option.asFloat( name ) ;
81  }
82  else {
83    width_ = 0.5 ; // default is half of median separation
84  }
85
86  name = "elongated" ;
87  if ( option.isDefined( name ) ) {
88    elongated_ = option.asBool( name ) ;
89  }
90  else {
91    elongated_ = False ; // default is two-dimensional processing
92  }
93
94  os_ << "OPTION SUMMARY: " << endl
95      << "   fraction=" << fraction_ << endl
96      << "   width=" << width_ << endl
97      << "   elongated=" << (elongated_ ? "True" : "False") << LogIO::POST ;
98}
99
100void GenericEdgeDetector::topixel()
101{
102//   os_.origin(LogOrigin( "GenericEdgeDetector", "topixel", WHERE )) ;
103
104  setup() ;
105  // using DirectionCoordinate
106  Matrix<Double> xform(2,2) ;
107  xform = 0.0 ;
108  xform.diagonal() = 1.0 ;
109  DirectionCoordinate coord( MDirection::J2000,
110                             Projection( Projection::SIN ),
111                             cenx_, ceny_,
112                             dx_, dy_,
113                             xform,
114                             0.5*Double(nx_-1),
115                             0.5*Double(ny_-1) ) ;
116  Double *pdir_p = new Double[dir_.nelements()] ;
117  pdir_.takeStorage( dir_.shape(), pdir_p, TAKE_OVER ) ;
118  uInt len = time_.nelements() ;
119  Bool b ;
120  Double *dir_p = dir_.getStorage( b ) ;
121  Double *wdir_p = dir_p ;
122  Vector<Double> world ;
123  Vector<Double> pixel ;
124  IPosition vshape( 1, 2 ) ;
125  for ( uInt i = 0 ; i < len ; i++ ) {
126    world.takeStorage( vshape, wdir_p, SHARE ) ;
127    pixel.takeStorage( vshape, pdir_p, SHARE ) ;
128    coord.toPixel( pixel, world ) ;
129    pdir_p += 2 ;
130    wdir_p += 2 ;
131  }
132  dir_.putStorage( dir_p, b ) ;
133}
134
135void GenericEdgeDetector::setup()
136{
137  os_.origin(LogOrigin( "GenericEdgeDetector", "setup", WHERE )) ;
138
139  Double xmax, xmin, ymax, ymin ;
140  minMax( xmin, xmax, dir_.row( 0 ) ) ;
141  minMax( ymin, ymax, dir_.row( 1 ) ) ;
142  Double wx = ( xmax - xmin ) * 1.1 ;
143  Double wy = ( ymax - ymin ) * 1.1 ;
144
145  cenx_ = 0.5 * ( xmin + xmax ) ;
146  ceny_ = 0.5 * ( ymin + ymax ) ;
147  Double decCorr = cos( ceny_ ) ;
148
149  uInt len = time_.nelements() ;
150  Matrix<Double> dd = dir_.copy() ;
151  for ( uInt i = len-1 ; i > 0 ; i-- ) {
152    //dd(0,i) = ( dd(0,i) - dd(0,i-1) ) * decCorr ;
153    dd(0,i) = ( dd(0,i) - dd(0,i-1) ) * cos( 0.5*(dd(1,i-1)+dd(1,i)) ) ;
154    dd(1,i) = dd(1,i) - dd(1,i-1) ;
155  }
156  Vector<Double> dr( len-1 ) ;
157  Bool b ;
158  const Double *dir_p = dd.getStorage( b ) ;
159  const Double *x_p = dir_p + 2 ;
160  const Double *y_p = dir_p + 3 ;
161  for ( uInt i = 0 ; i < len-1 ; i++ ) {
162    dr[i] = sqrt( (*x_p) * (*x_p) + (*y_p) * (*y_p) ) ;
163    x_p += 2 ;
164    y_p += 2 ;
165  }
166  dir_.freeStorage( dir_p, b ) ;
167  Double med = median( dr, False, True, True ) ;
168  dy_ = med * width_ ;
169  dx_ = dy_ / decCorr ;
170
171  Double nxTemp = ceil(wx / dx_);
172  Double nyTemp = ceil(wy / dy_);
173  if (nxTemp > (Double)UINT_MAX || nyTemp > (Double)UINT_MAX) {
174          throw AipsError("Error in setup: Too large number of pixels.");
175  }
176  nx_ = uInt( nxTemp ) ;
177  ny_ = uInt( nyTemp ) ;
178
179  pcenx_ = 0.5 * Double( nx_ - 1 ) ;
180  pceny_ = 0.5 * Double( ny_ - 1 ) ;
181
182  os_ << LogIO::DEBUGGING
183      << "rangex=(" << xmin << "," << xmax << ")" << endl
184      << "rangey=(" << ymin << "," << ymax << ")" << endl
185      << "median separation between pointings: " << med << endl
186      << "dx=" << dx_ << ", dy=" << dy_ << endl
187      << "wx=" << wx << ", wy=" << wy << endl
188      << "nx=" << nx_ << ", ny=" << ny_ << LogIO::POST ;
189}
190
191void GenericEdgeDetector::countup()
192{
193  os_.origin(LogOrigin( "GenericEdgeDetector", "countup", WHERE )) ;
194
195  try {
196          size_t n = (size_t)nx_ * (size_t)ny_;
197          uInt *a_p = new uInt[n] ;
198          apix_.takeStorage( IPosition(2,nx_,ny_), a_p, TAKE_OVER ) ;
199  }
200  catch (std::bad_alloc const &e) {
201          os_ << LogIO::SEVERE << "Failed to allocate working array" << LogIO::POST;
202          throw e;
203  }
204  catch (...) {
205          os_ << LogIO::SEVERE << "Failed due to unknown error" << LogIO::POST;
206          throw;
207  }
208  apix_ = 0 ;
209 
210  uInt len = time_.nelements() ;
211  uInt ix ;
212  uInt iy ;
213  // pdir_ is always contiguous
214  const Double *pdir_p = pdir_.data() ;
215  const Double *px_p = pdir_p ;
216  const Double *py_p = pdir_p + 1 ;
217  long offset ;
218  // apix_ is always contiguous
219  uInt *a_p = apix_.data();
220  for ( uInt i = 0 ; i < len ; i++ ) {
221    ix = uInt(round( *px_p )) ;
222    iy = uInt(round( *py_p )) ;
223    offset = ix + iy * nx_ ;
224    *(a_p+offset) += 1 ;
225    px_p += 2 ;
226    py_p += 2 ;
227  }
228
229  os_ << LogIO::DEBUGGING
230      << "a.max()=" << max(apix_) << ",a.min()=" << min(apix_) << LogIO::POST ;
231}
232
233void GenericEdgeDetector::thresholding()
234{
235  uInt len = apix_.nelements() ;
236  uInt *a_p = apix_.data() ;
237  for ( uInt i = 0 ; i < len ; i++ ) {
238    *a_p = ((*a_p > 0) ? 1 : 0) ;
239    a_p++ ;
240  }
241}
242
243void GenericEdgeDetector::labeling()
244{
245  os_.origin(LogOrigin( "GenericEdgeDetector", "labeling", WHERE )) ;
246
247  uInt n = 1 ;
248  uInt niter = 0 ;
249  const uInt maxiter = 100 ;
250  while ( n > 0 && niter < maxiter ) {
251    n = _labeling() ;
252    os_ << LogIO::DEBUGGING
253        << "cycle " << niter << ": labeled " << n << " pixels" << LogIO::POST ;
254    niter++ ;
255  }
256  if ( niter == maxiter ) {
257    // WARN
258    os_ << LogIO::WARN << "labeling not converged before maxiter=" << maxiter << LogIO::POST ;
259  }
260}
261
262uInt GenericEdgeDetector::_labeling()
263{
264  uInt n = 0 ;
265  for ( uInt ix = 0 ; ix < nx_ ; ix++ ) {
266    Vector<uInt> v( apix_.row( ix ) ) ;
267    uInt nx = __labeling( v ) ;
268    n += nx ;
269  }
270  for ( uInt iy = 0 ; iy < ny_ ; iy++ ) {
271    Vector<uInt> v( apix_.column( iy ) ) ;
272    uInt ny = __labeling( v ) ;
273    n += ny ;
274  }
275  return n ;
276}
277
278uInt GenericEdgeDetector::__labeling( Vector<uInt> &a )
279{
280  uInt n = 0 ;
281  if ( allEQ( a, n ) ) {
282    return n ;
283  }
284
285  uInt start ;
286  uInt end ;
287  _search( start, end, a ) ;
288  for ( uInt i = start+1 ; i < end ; i++ ) {
289    if ( a[i] == 0 ) {
290      a[i] = 1 ;
291      n++ ;
292    }
293  }
294  return n ;
295}
296
297void GenericEdgeDetector::_search( uInt &start,
298                                   uInt &end,
299                                   const Vector<uInt> &a )
300{
301  uInt n = a.nelements() ;
302  start = 0 ;
303  while( a[start] == 0 ) {
304    start++ ;
305  }
306  end = n - 1 ;
307  while( a[end] == 0 ) {
308    end-- ;
309  }
310}
311
312void GenericEdgeDetector::trimming()
313{
314  os_.origin(LogOrigin( "GenericEdgeDetector", "trimming", WHERE )) ;
315
316  const uInt n1 = sum( apix_ ) ;
317  const uInt nTrim = uInt(ceil( n1 * fraction_ )) ;
318  os_ << LogIO::DEBUGGING
319      << "number of nonzero pixel: " << n1 << endl
320      << "number of pixels to be trimmed: " << nTrim << LogIO::POST ;
321  uInt n = 0 ;
322  uInt niter = 0 ;
323  const uInt maxiter = 100 ;
324  if ( !elongated_ ) {
325    while ( n < nTrim && niter < maxiter ) {
326      uInt m = _trimming() ;
327      os_ << LogIO::DEBUGGING
328          << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
329      n += m ;
330      niter++ ;
331    }
332  }
333  else if ( nx_ > ny_ ) {
334    os_ << "1D triming along x-axis" << LogIO::POST ;
335    while ( n < nTrim && niter < maxiter ) {
336      uInt m = _trimming1DX() ;
337      os_ << LogIO::DEBUGGING
338          << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
339      n += m ;
340      niter++ ;
341    }
342  }
343  else { // nx_ < ny_
344    os_ << "1D triming along y-axis" << LogIO::POST ;
345    while ( n < nTrim && niter < maxiter ) {
346      uInt m = _trimming1DY() ;
347      os_ << LogIO::DEBUGGING
348          << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
349      n += m ;
350      niter++ ;
351    }
352  }
353  os_ << LogIO::DEBUGGING
354      << "number of pixels actually trimmed: " << n << LogIO::POST ;
355
356  if ( niter == maxiter ) {
357    // WARN
358    os_ << LogIO::WARN << "trimming not converged before maxiter=" << maxiter << LogIO::POST ;
359  }
360}
361
362uInt GenericEdgeDetector::_trimming()
363{
364  uInt n = 0 ;
365  Block<uInt> flatIdxList( apix_.nelements() ) ;
366  uInt start ;
367  uInt end ;
368  uInt flatIdx ;
369  for ( uInt ix = 0 ; ix < nx_ ; ix++ ) {
370    Vector<uInt> v( apix_.row( ix ) ) ;
371    if ( allEQ( v, (uInt)0 ) ) {
372      continue ;
373    }
374    _search( start, end, v ) ;
375    uInt offset = start * nx_ ;
376    flatIdx = offset + ix ;
377    flatIdxList[n++] = flatIdx ;
378    if ( start != end ) {
379      offset = end * nx_ ;
380      flatIdx = offset + ix ;
381      flatIdxList[n++] = flatIdx ;
382    }
383  }
384  for ( uInt iy = 0 ; iy < ny_ ; iy++ ) {
385    Vector<uInt> v( apix_.column( iy ) ) ;
386    if ( allEQ( v, (uInt)0 ) ) {
387      continue ;
388    }
389    uInt offset = iy * nx_ ;
390    _search( start, end, v ) ;
391    flatIdx = offset + start ;
392    flatIdxList[n++] = flatIdx ;
393    if ( start != end ) {
394      flatIdx = offset + end ;
395      flatIdxList[n++] = flatIdx ;
396    }
397  }
398  n = genSort( flatIdxList.storage(),
399               n,
400               Sort::Ascending,
401               Sort::QuickSort | Sort::NoDuplicates ) ;
402  Vector<uInt> v( IPosition(1,apix_.nelements()), apix_.data(), SHARE ) ;
403  const uInt *idx_p = flatIdxList.storage() ;
404  for ( uInt i = 0 ; i < n ; i++ ) {
405    v[*idx_p] = 0 ;
406    idx_p++ ;
407  }
408
409  return n ;
410}
411
412uInt GenericEdgeDetector::_trimming1DX()
413{
414  uInt n = 0 ;
415  const uInt nx = apix_.nrow() ;
416  Vector<uInt> v1, v2 ;
417  uInt ix, jx ;
418  for ( ix = 0 ; ix < nx_ ; ix++ ) {
419    v1.reference( apix_.row( ix ) ) ;
420    if ( anyNE( v1, n ) ) break ;
421  }
422  for ( jx = nx-1 ; jx > ix ; jx-- ) {
423    v2.reference( apix_.row( jx ) ) ;
424    if ( anyNE( v2, n ) ) break ;
425  }
426  n += _trimming1D( v1 ) ;
427  if ( ix != jx )
428    n+= _trimming1D( v2 ) ;
429 
430  return n ;
431}
432
433uInt GenericEdgeDetector::_trimming1DY()
434{
435  uInt n = 0 ;
436  const uInt ny = apix_.ncolumn() ;
437  Vector<uInt> v1, v2 ;
438  uInt iy, jy ;
439  for ( iy = 0 ; iy < ny_ ; iy++ ) {
440    v1.reference( apix_.column( iy ) ) ;
441    if ( anyNE( v1, n ) ) break ;
442  }
443  for ( jy = ny-1 ; jy > iy ; jy-- ) {
444    v2.reference( apix_.column( jy ) ) ;
445    if ( anyNE( v2, n ) ) break ;
446  }
447  n += _trimming1D( v1 ) ;
448  if ( iy != jy )
449    n+= _trimming1D( v2 ) ;
450 
451  return n ;
452}
453
454uInt GenericEdgeDetector::_trimming1D( Vector<uInt> &a )
455{
456  uInt len = a.nelements() ;
457  uInt n = 0 ;
458  for ( uInt i = 0 ; i < len ; i++ ) {
459    if ( a[i] == 1 ) {
460      a[i] = 0 ;
461      n++ ;
462    }
463  }
464 
465  return n ;
466}
467
468void GenericEdgeDetector::selection()
469{
470//   os_.origin(LogOrigin( "GenericEdgeDetector", "selection", WHERE )) ;
471
472  uInt nrow = pdir_.shape()[1] ;
473  const Double *px_p = pdir_.data() ;
474  const Double *py_p = px_p + 1 ;
475  Vector<uInt> v( IPosition(1,apix_.nelements()), apix_.data(), SHARE ) ;
476  uInt n = 0 ;
477  for ( uInt irow = 0 ; irow < nrow ; irow++ ) {
478    uInt idx = int(round(*px_p)) + int(round(*py_p)) * nx_ ;
479    if ( v[idx] == 0 ) {
480      tempuInt_[n++] = irow ;
481    }
482    px_p += 2 ;
483    py_p += 2 ;
484  }
485  off_ = vectorFromTempStorage( n ) ;
486}
487
488void GenericEdgeDetector::tuning()
489{
490  os_.origin(LogOrigin( "GenericEdgeDetector", "tuning", WHERE )) ;
491
492  const uInt len = off_.nelements() ;
493  if ( len == 0 )
494    return ;
495
496  Block<uInt> diff( len-1 ) ;
497  for ( uInt i = 0 ; i < len-1 ; i++ ) {
498    diff[i] = off_[i+1] - off_[i] ;
499  }
500  const uInt threshold = 3 ;
501  uInt n = 0 ;
502  for ( uInt i = 0 ; i < len ; i++ ) {
503    tempuInt_[n++] = off_[i] ;
504  }
505  for ( uInt i = 1 ; i < len ; i++ ) {
506    uInt ii = i - 1 ;
507    if ( diff[ii] != 1 && diff[ii] < threshold ) {
508      uInt t = off_[ii]+1 ;
509      uInt u = off_[i] ;
510      for ( uInt j = t ; j < u ; j++ ) {
511        os_ << LogIO::DEBUGGING
512            << "move " << j << " from ON to OFF" << LogIO::POST ;
513        tempuInt_[n++] = j ;
514      }
515    }
516  }
517  if ( n > len ) {
518    off_.resize() ;
519    off_ = vectorFromTempStorage( n ) ;
520  }
521}
522
523} // namespace asap
Note: See TracBrowser for help on using the repository browser.