source: trunk/src/GenericEdgeDetector.cpp@ 2614

Last change on this file since 2614 was 2614, checked in by Takeshi Nakazato, 13 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...

Bug fix on 1D trimming stage.


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