source: trunk/src/GenericEdgeDetector.cpp@ 3071

Last change on this file since 3071 was 3041, checked in by Takeshi Nakazato, 9 years ago

New Development: No

JIRA Issue: Yes CAS-7743

Ready for Test: Yes

Interface Changes: Yes/No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No

Module(s): Module Names change impacts.

Description: Describe your changes here...


Better handling of large number that exceeds a limit of uInt (unsigned int) and proper handling of possible memory allocation error.

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