source: trunk/src/GenericEdgeDetector.cpp@ 2634

Last change on this file since 2634 was 2632, 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: List test programs

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

DEC. correction on R.A. grid.


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 = fstr.substr(0,fstr.size()-1) ;
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_ ) * decCorr_ / 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 Double xmax, xmin, ymax, ymin ;
126 minMax( xmin, xmax, dir_.row( 0 ) ) ;
127 minMax( ymin, ymax, dir_.row( 1 ) ) ;
128 Double wx = ( xmax - xmin ) * 1.1 ;
129 Double wy = ( ymax - ymin ) * 1.1 ;
130
131 cenx_ = 0.5 * ( xmin + xmax ) ;
132 ceny_ = 0.5 * ( ymin + ymax ) ;
133 decCorr_ = 1.0 / cos( ceny_ ) ;
134
135 uInt len = time_.nelements() ;
136 Matrix<Double> dd = dir_.copy() ;
137 for ( uInt i = len-1 ; i > 0 ; i-- ) {
138 dd(0,i) = ( dd(0,i) - dd(0,i-1) ) * decCorr_ ;
139 dd(1,i) = dd(1,i) - dd(1,i-1) ;
140 }
141 Vector<Double> dr( len-1 ) ;
142 Bool b ;
143 const Double *dir_p = dd.getStorage( b ) ;
144 const Double *x_p = dir_p + 2 ;
145 const Double *y_p = dir_p + 3 ;
146 for ( uInt i = 0 ; i < len-1 ; i++ ) {
147 dr[i] = sqrt( (*x_p) * (*x_p) + (*y_p) * (*y_p) ) ;
148 x_p += 2 ;
149 y_p += 2 ;
150 }
151 dir_.freeStorage( dir_p, b ) ;
152 Double med = median( dr, False, True, True ) ;
153 dy_ = med * width_ ;
154 dx_ = dy_ * decCorr_ ;
155
156 nx_ = uInt( ceil( wx / dx_ ) ) ;
157 ny_ = uInt( ceil( wy / dy_ ) ) ;
158
159 pcenx_ = 0.5 * Double( nx_ - 1 ) ;
160 pceny_ = 0.5 * Double( ny_ - 1 ) ;
161
162 os_ << LogIO::DEBUGGING
163 << "rangex=(" << xmin << "," << xmax << ")" << endl
164 << "rangey=(" << ymin << "," << ymax << ")" << endl
165 << "median separation between pointings: " << med << endl
166 << "dx=" << dx_ << ", dy=" << dy_ << endl
167 << "wx=" << wx << ", wy=" << wy << endl
168 << "nx=" << nx_ << ", ny=" << ny_ << LogIO::POST ;
169}
170
171void GenericEdgeDetector::countup()
172{
173 os_.origin(LogOrigin( "GenericEdgeDetector", "countup", WHERE )) ;
174
175 uInt *a_p = new uInt[nx_*ny_] ;
176 apix_.takeStorage( IPosition(2,nx_,ny_), a_p, TAKE_OVER ) ;
177 apix_ = 0 ;
178
179 uInt len = time_.nelements() ;
180 uInt ix ;
181 uInt iy ;
182 // pdir_ is always contiguous
183 const Double *pdir_p = pdir_.data() ;
184 const Double *px_p = pdir_p ;
185 const Double *py_p = pdir_p + 1 ;
186 long offset ;
187 for ( uInt i = 0 ; i < len ; i++ ) {
188 ix = uInt(round( *px_p )) ;
189 iy = uInt(round( *py_p )) ;
190 offset = ix + iy * nx_ ;
191 *(a_p+offset) += 1 ;
192 px_p += 2 ;
193 py_p += 2 ;
194 }
195
196 os_ << LogIO::DEBUGGING
197 << "a.max()=" << max(apix_) << ",a.min()=" << min(apix_) << LogIO::POST ;
198}
199
200void GenericEdgeDetector::thresholding()
201{
202 uInt len = apix_.nelements() ;
203 uInt *a_p = apix_.data() ;
204 for ( uInt i = 0 ; i < len ; i++ ) {
205 *a_p = ((*a_p > 0) ? 1 : 0) ;
206 a_p++ ;
207 }
208}
209
210void GenericEdgeDetector::labeling()
211{
212 os_.origin(LogOrigin( "GenericEdgeDetector", "labeling", WHERE )) ;
213
214 uInt n = 1 ;
215 uInt niter = 0 ;
216 const uInt maxiter = 100 ;
217 while ( n > 0 && niter < maxiter ) {
218 n = _labeling() ;
219 os_ << LogIO::DEBUGGING
220 << "cycle " << niter << ": labeled " << n << " pixels" << LogIO::POST ;
221 niter++ ;
222 }
223 if ( niter == maxiter ) {
224 // WARN
225 os_ << LogIO::WARN << "labeling not converged before maxiter=" << maxiter << LogIO::POST ;
226 }
227}
228
229uInt GenericEdgeDetector::_labeling()
230{
231 uInt n = 0 ;
232 for ( uInt ix = 0 ; ix < nx_ ; ix++ ) {
233 Vector<uInt> v( apix_.row( ix ) ) ;
234 uInt nx = __labeling( v ) ;
235 n += nx ;
236 }
237 for ( uInt iy = 0 ; iy < ny_ ; iy++ ) {
238 Vector<uInt> v( apix_.column( iy ) ) ;
239 uInt ny = __labeling( v ) ;
240 n += ny ;
241 }
242 return n ;
243}
244
245uInt GenericEdgeDetector::__labeling( Vector<uInt> &a )
246{
247 uInt n = 0 ;
248 if ( allEQ( a, n ) ) {
249 return n ;
250 }
251
252 uInt start ;
253 uInt end ;
254 _search( start, end, a ) ;
255 for ( uInt i = start+1 ; i < end ; i++ ) {
256 if ( a[i] == 0 ) {
257 a[i] = 1 ;
258 n++ ;
259 }
260 }
261 return n ;
262}
263
264void GenericEdgeDetector::_search( uInt &start,
265 uInt &end,
266 const Vector<uInt> &a )
267{
268 uInt n = a.nelements() ;
269 start = 0 ;
270 while( a[start] == 0 ) {
271 start++ ;
272 }
273 end = n - 1 ;
274 while( a[end] == 0 ) {
275 end-- ;
276 }
277}
278
279void GenericEdgeDetector::trimming()
280{
281 os_.origin(LogOrigin( "GenericEdgeDetector", "trimming", WHERE )) ;
282
283 const uInt n1 = sum( apix_ ) ;
284 const uInt nTrim = uInt(ceil( n1 * fraction_ )) ;
285 os_ << LogIO::DEBUGGING
286 << "number of nonzero pixel: " << n1 << endl
287 << "number of pixels to be trimmed: " << nTrim << LogIO::POST ;
288 uInt n = 0 ;
289 uInt niter = 0 ;
290 const uInt maxiter = 100 ;
291 if ( !elongated_ ) {
292 while ( n < nTrim && niter < maxiter ) {
293 uInt m = _trimming() ;
294 os_ << LogIO::DEBUGGING
295 << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
296 n += m ;
297 niter++ ;
298 }
299 }
300 else if ( nx_ > ny_ ) {
301 os_ << "1D triming along x-axis" << LogIO::POST ;
302 while ( n < nTrim && niter < maxiter ) {
303 uInt m = _trimming1DX() ;
304 os_ << LogIO::DEBUGGING
305 << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
306 n += m ;
307 niter++ ;
308 }
309 }
310 else { // nx_ < ny_
311 os_ << "1D triming along y-axis" << LogIO::POST ;
312 while ( n < nTrim && niter < maxiter ) {
313 uInt m = _trimming1DY() ;
314 os_ << LogIO::DEBUGGING
315 << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
316 n += m ;
317 niter++ ;
318 }
319 }
320 os_ << LogIO::DEBUGGING
321 << "number of pixels actually trimmed: " << n << LogIO::POST ;
322
323 if ( niter == maxiter ) {
324 // WARN
325 os_ << LogIO::WARN << "trimming not converged before maxiter=" << maxiter << LogIO::POST ;
326 }
327}
328
329uInt GenericEdgeDetector::_trimming()
330{
331 uInt n = 0 ;
332 Block<uInt> flatIdxList( apix_.nelements() ) ;
333 uInt start ;
334 uInt end ;
335 uInt flatIdx ;
336 for ( uInt ix = 0 ; ix < nx_ ; ix++ ) {
337 Vector<uInt> v( apix_.row( ix ) ) ;
338 if ( allEQ( v, (uInt)0 ) ) {
339 continue ;
340 }
341 _search( start, end, v ) ;
342 uInt offset = start * nx_ ;
343 flatIdx = offset + ix ;
344 flatIdxList[n++] = flatIdx ;
345 if ( start != end ) {
346 offset = end * nx_ ;
347 flatIdx = offset + ix ;
348 flatIdxList[n++] = flatIdx ;
349 }
350 }
351 for ( uInt iy = 0 ; iy < ny_ ; iy++ ) {
352 Vector<uInt> v( apix_.column( iy ) ) ;
353 if ( allEQ( v, (uInt)0 ) ) {
354 continue ;
355 }
356 uInt offset = iy * nx_ ;
357 _search( start, end, v ) ;
358 flatIdx = offset + start ;
359 flatIdxList[n++] = flatIdx ;
360 if ( start != end ) {
361 flatIdx = offset + end ;
362 flatIdxList[n++] = flatIdx ;
363 }
364 }
365 n = genSort( flatIdxList.storage(),
366 n,
367 Sort::Ascending,
368 Sort::QuickSort | Sort::NoDuplicates ) ;
369 Vector<uInt> v( IPosition(1,apix_.nelements()), apix_.data(), SHARE ) ;
370 const uInt *idx_p = flatIdxList.storage() ;
371 for ( uInt i = 0 ; i < n ; i++ ) {
372 v[*idx_p] = 0 ;
373 idx_p++ ;
374 }
375
376 return n ;
377}
378
379uInt GenericEdgeDetector::_trimming1DX()
380{
381 uInt n = 0 ;
382 const uInt nx = apix_.nrow() ;
383 Vector<uInt> v1, v2 ;
384 uInt ix, jx ;
385 for ( ix = 0 ; ix < nx_ ; ix++ ) {
386 v1.reference( apix_.row( ix ) ) ;
387 if ( anyNE( v1, n ) ) break ;
388 }
389 for ( jx = nx-1 ; jx > ix ; jx-- ) {
390 v2.reference( apix_.row( jx ) ) ;
391 if ( anyNE( v2, n ) ) break ;
392 }
393 n += _trimming1D( v1 ) ;
394 if ( ix != jx )
395 n+= _trimming1D( v2 ) ;
396
397 return n ;
398}
399
400uInt GenericEdgeDetector::_trimming1DY()
401{
402 uInt n = 0 ;
403 const uInt ny = apix_.ncolumn() ;
404 Vector<uInt> v1, v2 ;
405 uInt iy, jy ;
406 for ( iy = 0 ; iy < ny_ ; iy++ ) {
407 v1.reference( apix_.column( iy ) ) ;
408 if ( anyNE( v1, n ) ) break ;
409 }
410 for ( jy = ny-1 ; jy > iy ; jy-- ) {
411 v2.reference( apix_.column( jy ) ) ;
412 if ( anyNE( v2, n ) ) break ;
413 }
414 n += _trimming1D( v1 ) ;
415 if ( iy != jy )
416 n+= _trimming1D( v2 ) ;
417
418 return n ;
419}
420
421uInt GenericEdgeDetector::_trimming1D( Vector<uInt> &a )
422{
423 uInt len = a.nelements() ;
424 uInt n = 0 ;
425 for ( uInt i = 0 ; i < len ; i++ ) {
426 if ( a[i] == 1 ) {
427 a[i] = 0 ;
428 n++ ;
429 }
430 }
431
432 return n ;
433}
434
435void GenericEdgeDetector::selection()
436{
437// os_.origin(LogOrigin( "GenericEdgeDetector", "selection", WHERE )) ;
438
439 uInt nrow = pdir_.shape()[1] ;
440 const Double *px_p = pdir_.data() ;
441 const Double *py_p = px_p + 1 ;
442 Vector<uInt> v( IPosition(1,apix_.nelements()), apix_.data(), SHARE ) ;
443 uInt n = 0 ;
444 for ( uInt irow = 0 ; irow < nrow ; irow++ ) {
445 uInt idx = int(round(*px_p)) + int(round(*py_p)) * nx_ ;
446 if ( v[idx] == 0 ) {
447 tempuInt_[n++] = irow ;
448 }
449 px_p += 2 ;
450 py_p += 2 ;
451 }
452 off_ = vectorFromTempStorage( n ) ;
453}
454
455void GenericEdgeDetector::tuning()
456{
457 os_.origin(LogOrigin( "GenericEdgeDetector", "tuning", WHERE )) ;
458
459 const uInt len = off_.nelements() ;
460 if ( len == 0 )
461 return ;
462
463 Block<uInt> diff( len-1 ) ;
464 for ( uInt i = 0 ; i < len-1 ; i++ ) {
465 diff[i] = off_[i+1] - off_[i] ;
466 }
467 const uInt threshold = 3 ;
468 uInt n = 0 ;
469 for ( uInt i = 0 ; i < len ; i++ ) {
470 tempuInt_[n++] = off_[i] ;
471 }
472 for ( uInt i = 1 ; i < len ; i++ ) {
473 uInt ii = i - 1 ;
474 if ( diff[ii] != 1 && diff[ii] < threshold ) {
475 uInt t = off_[ii]+1 ;
476 uInt u = off_[i] ;
477 for ( uInt j = t ; j < u ; j++ ) {
478 os_ << LogIO::DEBUGGING
479 << "move " << j << " from ON to OFF" << LogIO::POST ;
480 tempuInt_[n++] = j ;
481 }
482 }
483 }
484 if ( n > len ) {
485 off_.resize() ;
486 off_ = vectorFromTempStorage( n ) ;
487 }
488}
489
490} // namespace asap
Note: See TracBrowser for help on using the repository browser.