source: trunk/src/GenericEdgeDetector.cpp @ 2615

Last change on this file since 2615 was 2615, checked in by Takeshi Nakazato, 12 years ago

New Development: No

JIRA Issue: Yes CAS-2825

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: not available yet

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Logging updated. Priorities for most of the logs are changed to
DEBUGGING since those are mainly for debug use.


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