source: trunk/src/GenericEdgeDetector.cpp@ 2616

Last change on this file since 2616 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
RevLine 
[2613]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{
[2615]36 os_.origin(LogOrigin( "GenericEdgeDetector", "detect", WHERE )) ;
37
[2613]38 initDetect() ;
39
40 topixel() ;
41 countup() ;
42 thresholding() ;
43 labeling() ;
44 trimming() ;
45 selection() ;
46 tuning() ;
47
[2615]48 os_ << LogIO::DEBUGGING
49 << "Detected " << off_.nelements() << " integrations as OFF" << LogIO::POST ;
50
[2613]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 ) ) {
[2614]84 elongated_ = option.asBool( name ) ;
[2613]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{
[2615]98// os_.origin(LogOrigin( "GenericEdgeDetector", "topixel", WHERE )) ;
[2613]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
[2615]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 ;
[2613]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
[2615]195 os_ << LogIO::DEBUGGING
196 << "a.max()=" << max(apix_) << ",a.min()=" << min(apix_) << LogIO::POST ;
[2613]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 ;
[2615]215 const uInt maxiter = 100 ;
[2613]216 while ( n > 0 && niter < maxiter ) {
217 n = _labeling( apix_ ) ;
[2615]218 os_ << LogIO::DEBUGGING
219 << "cycle " << niter << ": labeled " << n << " pixels" << LogIO::POST ;
[2613]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_ )) ;
[2615]284 os_ << LogIO::DEBUGGING
285 << "number of nonzero pixel: " << n1 << endl
286 << "number of pixels to be trimmed: " << nTrim << LogIO::POST ;
[2613]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_ ) ;
[2615]293 os_ << LogIO::DEBUGGING
294 << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
[2613]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_ ) ;
[2615]303 os_ << LogIO::DEBUGGING
304 << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
[2613]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_ ) ;
[2615]313 os_ << LogIO::DEBUGGING
314 << "cycle " << niter << ": trimmed " << m << " pixels" << LogIO::POST ;
[2613]315 n += m ;
316 niter++ ;
317 }
318 }
[2615]319 os_ << LogIO::DEBUGGING
320 << "number of pixels actually trimmed: " << n << LogIO::POST ;
[2613]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 }
[2614]390 for ( jx = nx-1 ; jx > ix ; jx-- ) {
[2613]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 }
[2614]411 for ( jy = ny-1 ; jy > iy ; jy-- ) {
[2613]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{
[2615]438// os_.origin(LogOrigin( "GenericEdgeDetector", "selection", WHERE )) ;
[2613]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
[2615]464 Vector<uInt> diff( len-1 ) ;
465 for ( uInt i = 0 ; i < len-1 ; i++ ) {
466 diff[i] = off_[i+1] - off_[i] ;
[2613]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++ ) {
[2615]474 uInt ii = i - 1 ;
475 if ( diff[ii] != 1 && diff[ii] < threshold ) {
476 uInt t = off_[ii]+1 ;
[2613]477 uInt u = off_[i] ;
478 for ( uInt j = t ; j < u ; j++ ) {
[2615]479 os_ << LogIO::DEBUGGING
480 << "move " << j << " from ON to OFF" << LogIO::POST ;
[2613]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.