source: trunk/src/GenericEdgeDetector.cpp@ 2623

Last change on this file since 2623 was 2617, 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

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Minor refactoring.


File size: 11.6 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 ) {
[2617]217 n = _labeling() ;
[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
[2617]228uInt GenericEdgeDetector::_labeling()
[2613]229{
230 uInt n = 0 ;
231 for ( uInt ix = 0 ; ix < nx_ ; ix++ ) {
[2617]232 Vector<uInt> v( apix_.row( ix ) ) ;
[2613]233 uInt nx = __labeling( v ) ;
234 n += nx ;
235 }
236 for ( uInt iy = 0 ; iy < ny_ ; iy++ ) {
[2617]237 Vector<uInt> v( apix_.column( iy ) ) ;
[2613]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 ) {
[2617]292 uInt m = _trimming() ;
[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 ) {
[2617]302 uInt m = _trimming1DX() ;
[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 ) {
[2617]312 uInt m = _trimming1DY() ;
[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
[2617]328uInt GenericEdgeDetector::_trimming()
[2613]329{
330 uInt n = 0 ;
[2617]331 Block<uInt> flatIdxList( apix_.nelements() ) ;
[2613]332 uInt start ;
333 uInt end ;
334 uInt flatIdx ;
[2617]335 for ( uInt ix = 0 ; ix < nx_ ; ix++ ) {
336 Vector<uInt> v( apix_.row( ix ) ) ;
[2613]337 if ( allEQ( v, (uInt)0 ) ) {
338 continue ;
339 }
340 _search( start, end, v ) ;
[2617]341 uInt offset = start * nx_ ;
[2613]342 flatIdx = offset + ix ;
343 flatIdxList[n++] = flatIdx ;
344 if ( start != end ) {
[2617]345 offset = end * nx_ ;
[2613]346 flatIdx = offset + ix ;
347 flatIdxList[n++] = flatIdx ;
348 }
349 }
[2617]350 for ( uInt iy = 0 ; iy < ny_ ; iy++ ) {
351 Vector<uInt> v( apix_.column( iy ) ) ;
[2613]352 if ( allEQ( v, (uInt)0 ) ) {
353 continue ;
354 }
[2617]355 uInt offset = iy * nx_ ;
[2613]356 _search( start, end, v ) ;
357 flatIdx = offset + start ;
358 flatIdxList[n++] = flatIdx ;
359 if ( start != end ) {
360 flatIdx = offset + end ;
361 flatIdxList[n++] = flatIdx ;
362 }
363 }
364 n = genSort( flatIdxList.storage(),
365 n,
366 Sort::Ascending,
367 Sort::QuickSort | Sort::NoDuplicates ) ;
[2617]368 Vector<uInt> v( IPosition(1,apix_.nelements()), apix_.data(), SHARE ) ;
[2613]369 const uInt *idx_p = flatIdxList.storage() ;
370 for ( uInt i = 0 ; i < n ; i++ ) {
371 v[*idx_p] = 0 ;
372 idx_p++ ;
373 }
374
375 return n ;
376}
377
[2617]378uInt GenericEdgeDetector::_trimming1DX()
[2613]379{
380 uInt n = 0 ;
[2617]381 const uInt nx = apix_.nrow() ;
[2613]382 Vector<uInt> v1, v2 ;
383 uInt ix, jx ;
[2617]384 for ( ix = 0 ; ix < nx_ ; ix++ ) {
385 v1.reference( apix_.row( ix ) ) ;
[2613]386 if ( anyNE( v1, n ) ) break ;
387 }
[2614]388 for ( jx = nx-1 ; jx > ix ; jx-- ) {
[2617]389 v2.reference( apix_.row( jx ) ) ;
[2613]390 if ( anyNE( v2, n ) ) break ;
391 }
392 n += _trimming1D( v1 ) ;
393 if ( ix != jx )
394 n+= _trimming1D( v2 ) ;
395
396 return n ;
397}
398
[2617]399uInt GenericEdgeDetector::_trimming1DY()
[2613]400{
401 uInt n = 0 ;
[2617]402 const uInt ny = apix_.ncolumn() ;
[2613]403 Vector<uInt> v1, v2 ;
404 uInt iy, jy ;
[2617]405 for ( iy = 0 ; iy < ny_ ; iy++ ) {
406 v1.reference( apix_.column( iy ) ) ;
[2613]407 if ( anyNE( v1, n ) ) break ;
408 }
[2614]409 for ( jy = ny-1 ; jy > iy ; jy-- ) {
[2617]410 v2.reference( apix_.column( jy ) ) ;
[2613]411 if ( anyNE( v2, n ) ) break ;
412 }
413 n += _trimming1D( v1 ) ;
414 if ( iy != jy )
415 n+= _trimming1D( v2 ) ;
416
417 return n ;
418}
419
420uInt GenericEdgeDetector::_trimming1D( Vector<uInt> &a )
421{
422 uInt len = a.nelements() ;
423 uInt n = 0 ;
424 for ( uInt i = 0 ; i < len ; i++ ) {
425 if ( a[i] == 1 ) {
426 a[i] = 0 ;
427 n++ ;
428 }
429 }
430
431 return n ;
432}
433
434void GenericEdgeDetector::selection()
435{
[2615]436// os_.origin(LogOrigin( "GenericEdgeDetector", "selection", WHERE )) ;
[2613]437
438 uInt nrow = pdir_.shape()[1] ;
439 const Double *px_p = pdir_.data() ;
440 const Double *py_p = px_p + 1 ;
441 Vector<uInt> v( IPosition(1,apix_.nelements()), apix_.data(), SHARE ) ;
442 uInt n = 0 ;
443 for ( uInt irow = 0 ; irow < nrow ; irow++ ) {
444 uInt idx = int(round(*px_p)) + int(round(*py_p)) * nx_ ;
445 if ( v[idx] == 0 ) {
446 tempuInt_[n++] = irow ;
447 }
448 px_p += 2 ;
449 py_p += 2 ;
450 }
451 off_ = vectorFromTempStorage( n ) ;
452}
453
454void GenericEdgeDetector::tuning()
455{
456 os_.origin(LogOrigin( "GenericEdgeDetector", "tuning", WHERE )) ;
457
458 const uInt len = off_.nelements() ;
459 if ( len == 0 )
460 return ;
461
[2617]462 Block<uInt> diff( len-1 ) ;
[2615]463 for ( uInt i = 0 ; i < len-1 ; i++ ) {
464 diff[i] = off_[i+1] - off_[i] ;
[2613]465 }
466 const uInt threshold = 3 ;
467 uInt n = 0 ;
468 for ( uInt i = 0 ; i < len ; i++ ) {
469 tempuInt_[n++] = off_[i] ;
470 }
471 for ( uInt i = 1 ; i < len ; i++ ) {
[2615]472 uInt ii = i - 1 ;
473 if ( diff[ii] != 1 && diff[ii] < threshold ) {
474 uInt t = off_[ii]+1 ;
[2613]475 uInt u = off_[i] ;
476 for ( uInt j = t ; j < u ; j++ ) {
[2615]477 os_ << LogIO::DEBUGGING
478 << "move " << j << " from ON to OFF" << LogIO::POST ;
[2613]479 tempuInt_[n++] = j ;
480 }
481 }
482 }
483 if ( n > len ) {
484 off_.resize() ;
485 off_ = vectorFromTempStorage( n ) ;
486 }
487}
488
489} // namespace asap
Note: See TracBrowser for help on using the repository browser.