Line data Source code
1 : //# ImageDecomposer.cc: defines the ImageDecomposer class
2 : //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2002
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id: ImageDecomposer.tcc 20739 2009-09-29 01:15:15Z Malte.Marquarding $
27 :
28 : #include <imageanalysis/ImageAnalysis/ImageDecomposer.h>
29 :
30 : #include <casacore/casa/Arrays/Slicer.h>
31 : #include <casacore/casa/Arrays/Cube.h>
32 : #include <casacore/casa/IO/ArrayIO.h>
33 : #include <casacore/lattices/Lattices/TiledShape.h>
34 : #include <casacore/scimath/Fitting/FitGaussian.h>
35 : #include <casacore/coordinates/Coordinates/CoordinateSystem.h>
36 : #include <casacore/lattices/LRegions/LatticeRegion.h>
37 : #include <casacore/lattices/LRegions/LCMask.h>
38 : #include <casacore/lattices/LEL/LatticeExpr.h>
39 : #include <casacore/lattices/LEL/LatticeExprNode.h>
40 : #include <casacore/lattices/Lattices/LatticeIterator.h>
41 : #include <casacore/casa/BasicMath/Math.h>
42 : #include <casacore/casa/Utilities/Assert.h>
43 : #include <casacore/images/Images/TempImage.h>
44 : #include <casacore/images/Images/SubImage.h>
45 :
46 :
47 : namespace casa {
48 :
49 : template <class T>
50 0 : ImageDecomposer<T>::ImageDecomposer(const casacore::ImageInterface<T>& image)
51 0 : : itsImagePtr(image.cloneII()),
52 0 : itsMapPtr(0),
53 0 : itsShape(itsImagePtr->shape()),
54 0 : itsDim(itsShape.nelements()),
55 0 : itsNRegions(0),
56 0 : itsNComponents(0),
57 0 : itsDeblendIt(true),
58 0 : itsThresholdVal(0.1),
59 0 : itsNContour(11),
60 0 : itsMinRange(2),
61 0 : itsNAxis(2),
62 0 : itsFitIt(true),
63 0 : itsMaximumRMS(0.1),
64 0 : itsMaxRetries(-1),
65 0 : itsMaxIter(256),
66 0 : itsConvCriteria(0.001)
67 : {
68 0 : itsMapPtr = new casacore::TempLattice<casacore::Int>(casacore::TiledShape(itsShape), 1);
69 0 : if (!itsMapPtr) {
70 0 : delete itsImagePtr;
71 0 : throw(casacore::AipsError("Failed to create internal TempLattice"));
72 : }
73 : //
74 0 : itsMapPtr->set(0);
75 0 : }
76 :
77 :
78 : template <class T>
79 0 : ImageDecomposer<T>::ImageDecomposer(const ImageDecomposer<T>& other)
80 :
81 0 : : itsImagePtr(other.itsImagePtr->cloneII()),
82 0 : itsMapPtr(0),
83 0 : itsShape(other.itsShape),
84 0 : itsDim(other.itsDim),
85 0 : itsNRegions(0),
86 0 : itsNComponents(0)
87 : {
88 0 : itsMapPtr = new casacore::TempLattice<casacore::Int>(casacore::TiledShape(itsShape), 1);
89 0 : if (!itsMapPtr) {
90 0 : delete itsImagePtr;
91 0 : throw(casacore::AipsError("Failed to create internal TempLattice"));
92 : }
93 : //
94 0 : itsNRegions = other.itsNRegions;
95 0 : itsNComponents = other.itsNComponents;
96 0 : itsList = other.itsList.copy();
97 :
98 0 : copyOptions(other);
99 :
100 : // Copy values from other.itsMapPtr
101 :
102 0 : itsMapPtr->copyData(*(other.itsMapPtr));
103 0 : }
104 : /*
105 : template <class T>
106 : ImageDecomposer<T> &ImageDecomposer<T>::operator=(const ImageDecomposer<T> &other)
107 : {
108 : if (this != &other) {
109 : delete itsImagePtr;
110 : delete itsMapPtr;
111 :
112 : itsImagePtr = other.itsImagePtr->cloneII();
113 : itsShape = other.itsShape;
114 : itsDim = other.itsDim;
115 : itsNRegions = 0;
116 : itsNComponents = 0;
117 :
118 : itsMapPtr = new casacore::TempLattice<casacore::Int>(casacore::TiledShape(itsShape), 1);
119 : itsMapPtr->copyData(*(other.itsMapPtr));
120 : itsList = other.itsList.copy();
121 :
122 : copyOptions(other);
123 : }
124 : return *this;
125 : }
126 : */
127 :
128 : template <class T>
129 0 : ImageDecomposer<T>::~ImageDecomposer()
130 : {
131 0 : if (itsImagePtr) {
132 0 : delete itsImagePtr;
133 0 : itsImagePtr = 0;
134 : }
135 0 : if (itsMapPtr) {
136 0 : delete itsMapPtr;
137 0 : itsMapPtr = 0;
138 : }
139 0 : }
140 :
141 : // Basic set/get functions
142 : // -----------------------
143 :
144 : /*
145 : template <class T>
146 : void ImageDecomposer<T>::setImage(casacore::ImageInterface<T>& image)
147 : {
148 : if (itsImagePtr) {
149 : delete itsImagePtr;
150 : itsImagePtr = 0;
151 : }
152 : if (itsMapPtr) {
153 : delete itsMapPtr;
154 : itsMapPtr = 0;
155 : }
156 : //
157 : itsImagePtr = image.cloneII();
158 : itsShape.resize(0); //necessary for dimension change
159 : itsShape = itsImagePtr->shape();
160 : itsDim = itsShape.nelements();
161 : itsNRegions = 0;
162 : itsNComponents = 0;
163 : //
164 : itsMapPtr = new casacore::TempLattice<casacore::Int>(casacore::TiledShape(itsShape), 1);
165 : if (!itsMapPtr) {
166 : delete itsImagePtr;
167 : throw(casacore::AipsError("Failed to create internal TempLattice"));
168 : }
169 : itsMapPtr->set(0);
170 : }
171 : */
172 :
173 : template <class T>
174 0 : void ImageDecomposer<T>::setDeblend(casacore::Bool deblendIt)
175 : {
176 0 : itsDeblendIt = deblendIt;
177 0 : return;
178 : }
179 :
180 : template <class T>
181 0 : void ImageDecomposer<T>::setDeblendOptions(T thresholdVal,casacore::uInt nContour,
182 : casacore::Int minRange, casacore::Int nAxis)
183 : {
184 0 : itsThresholdVal = thresholdVal;
185 0 : itsNContour = nContour;
186 0 : itsMinRange = minRange;
187 0 : itsNAxis = nAxis;
188 0 : return;
189 : }
190 :
191 : template <class T>
192 0 : void ImageDecomposer<T>::setFit(casacore::Bool fitIt)
193 : {
194 0 : itsFitIt = fitIt;
195 0 : return;
196 : }
197 :
198 : template <class T>
199 : void ImageDecomposer<T>::setFitOptions(T maximumRMS, casacore::Int maxRetries,
200 : casacore::uInt maxIter, T convCriteria)
201 : {
202 : itsMaximumRMS = maximumRMS;
203 : itsMaxRetries = maxRetries;
204 : itsMaxIter = maxIter;
205 : itsConvCriteria = convCriteria;
206 : return;
207 : }
208 :
209 :
210 : template <class T>
211 0 : void ImageDecomposer<T>::copyOptions(const ImageDecomposer<T> &other)
212 : {
213 0 : itsDeblendIt = other.itsDeblendIt;
214 0 : itsThresholdVal = other.itsThresholdVal;
215 0 : itsNContour = other.itsNContour;
216 0 : itsMinRange = other.itsMinRange;
217 0 : itsNAxis = other.itsNAxis;
218 0 : itsFitIt = other.itsFitIt;
219 0 : itsMaximumRMS = other.itsMaximumRMS;
220 0 : itsMaxRetries = other.itsMaxRetries;
221 0 : itsMaxIter = other.itsMaxIter;
222 0 : itsConvCriteria = other.itsConvCriteria;
223 0 : return;
224 : }
225 :
226 :
227 : template <class T>
228 : int ImageDecomposer<T>::getCell(casacore::Int x, casacore::Int y) const
229 : {
230 : return itsMapPtr->getAt(casacore::IPosition(2,x,y));
231 : }
232 :
233 : template <class T>
234 : int ImageDecomposer<T>::getCell(casacore::Int x, casacore::Int y, casacore::Int z) const
235 : {
236 : return itsMapPtr->getAt(casacore::IPosition(3,x,y,z));
237 : }
238 : template <class T>
239 0 : int ImageDecomposer<T>::getCell(const casacore::IPosition& coord) const
240 : {
241 0 : return itsMapPtr->getAt(coord); //note: 3D casacore::IPosition works on 2D image
242 : }
243 :
244 :
245 : template <class T>
246 : void ImageDecomposer<T>::setCell(casacore::Int x, casacore::Int y, casacore::Int sval)
247 : {
248 : itsMapPtr->putAt(sval, casacore::IPosition(2,x,y));
249 : return;
250 : }
251 : template <class T>
252 : void ImageDecomposer<T>::setCell(casacore::Int x, casacore::Int y, casacore::Int z, casacore::Int sval)
253 : {
254 : itsMapPtr->putAt(sval, casacore::IPosition(3,x,y,z));
255 : return;
256 : }
257 : template <class T>
258 0 : void ImageDecomposer<T>::setCell(const casacore::IPosition& coord, casacore::Int sval)
259 : {
260 0 : itsMapPtr->putAt(sval, coord);
261 0 : return;
262 : }
263 :
264 : template <class T>
265 0 : casacore::IPosition ImageDecomposer<T>::shape() const
266 : {
267 0 : return itsShape;
268 : }
269 :
270 : template <class T>
271 0 : int ImageDecomposer<T>::shape(casacore::uInt axis) const
272 : {
273 0 : if (itsDim > axis) return itsShape(axis);
274 0 : return 1;
275 : }
276 :
277 : //The numRegions and numComponents functions are both getters for their
278 : //respective variables and flags telling whether the image has been derived
279 : //and/or decomposed.
280 :
281 : template <class T>
282 0 : casacore::uInt ImageDecomposer<T>::numRegions() const
283 : {
284 0 : return itsNRegions;
285 : }
286 :
287 : template <class T>
288 0 : casacore::uInt ImageDecomposer<T>::numComponents() const
289 : {
290 0 : return itsNComponents;
291 : }
292 :
293 : template <class T>
294 0 : bool ImageDecomposer<T>::isDerived() const
295 : {
296 0 : return itsNRegions>0;
297 : }
298 :
299 : template <class T>
300 0 : bool ImageDecomposer<T>::isDecomposed() const
301 : {
302 0 : return itsNComponents>0;
303 : }
304 :
305 : template <class T>
306 0 : T ImageDecomposer<T>::getImageVal(casacore::Int x, casacore::Int y) const
307 : {
308 0 : return getImageVal(casacore::IPosition(2,x,y));
309 : }
310 :
311 : template <class T>
312 0 : T ImageDecomposer<T>::getImageVal(casacore::Int x, casacore::Int y, casacore::Int z) const
313 : {
314 0 : return getImageVal(casacore::IPosition(3,x,y,z));
315 : }
316 :
317 : template <class T>
318 0 : T ImageDecomposer<T>::getImageVal(casacore::IPosition coord) const
319 : {
320 0 : return itsImagePtr->getAt(coord);
321 : }
322 :
323 :
324 : template <class T>
325 : int ImageDecomposer<T>::getContourVal(casacore::Int x, casacore::Int y, const casacore::Vector<T>& clevels) const
326 : {
327 : return getContourVal(casacore::IPosition(2,x,y), clevels);
328 : }
329 :
330 : template <class T>
331 : int ImageDecomposer<T>::getContourVal(casacore::Int x, casacore::Int y, casacore::Int z,
332 : const casacore::Vector<T>& clevels) const
333 : {
334 : return getContourVal(casacore::IPosition(3,x,y,z), clevels);
335 : }
336 :
337 : template <class T>
338 : int ImageDecomposer<T>::getContourVal(casacore::IPosition coord,
339 : const casacore::Vector<T>& clevels) const
340 : {
341 : T val = itsImagePtr->getAt(coord);
342 : for (casacore::uInt c = 0; c < clevels.nelements(); c++) {
343 : if (val < clevels(c)) return c - 1;
344 : }
345 : return clevels.nelements()-1;
346 : }
347 :
348 : template <class T>
349 0 : int ImageDecomposer<T>::getContourVal(T val, const casacore::Vector<T>& clevels) const
350 : {
351 0 : for (casacore::uInt c = 0; c < clevels.nelements(); c++) {
352 0 : if (val < clevels(c)) return c - 1;
353 : }
354 0 : return clevels.nelements()-1;
355 : }
356 :
357 : template <class T>
358 : casacore::Vector<T> ImageDecomposer<T>::autoContour(T mincon, T maxcon, T inc) const
359 : {
360 : if (inc == T(0)) {
361 : throw(casacore::AipsError("Vector<T> ImageDecomposer<T>::autocontour"
362 : "T mincon, T maxcon, T inc) - inc cannot be zero"));
363 : }
364 : if ((maxcon - mincon) * inc < 0) inc = -inc;
365 :
366 : casacore::Int c = 0;
367 : for (T cl = mincon; cl <= maxcon; cl += inc) c++;
368 :
369 : casacore::Vector<T> contours(c);
370 : c = 0;
371 : for (T cl = mincon; cl <= maxcon; cl += inc) {
372 : contours(c++) = cl;
373 : }
374 : return contours;
375 : }
376 :
377 : template <class T>
378 0 : casacore::Vector<T> ImageDecomposer<T>::autoContour(casacore::Int nContours, T minValue) const
379 : {
380 : // IMPR: a noise estimate to determine default value of lowest contour
381 : // would be useful.
382 :
383 0 : casacore::Vector<T> contours(nContours);
384 : T maxValue;
385 : //
386 0 : maxValue = findAreaGlobalMax(casacore::IPosition(itsDim,0), shape());
387 0 : maxValue -= (maxValue-minValue)/((nContours-1)*3);
388 : //cerr << "Autocontour: minvalue, maxvalue = " << minValue << ", " << maxValue << endl;
389 :
390 : // Make maximum contour ~1/3 contour increment less than max value of image
391 :
392 0 : for (casacore::Int i=0; i<nContours; i++) {
393 0 : contours(i) = minValue + (maxValue-minValue)*i/(nContours-1);
394 : }
395 : //
396 0 : return contours;
397 0 : }
398 :
399 : template <class T>
400 : casacore::Vector<T> ImageDecomposer<T>::autoContour(const casacore::Function1D<T>& fn,
401 : casacore::Int ncontours, T minvalue) const
402 : {
403 : // NOTE: This function has not been recently tested.
404 :
405 : casacore::Vector<T> contours(ncontours);
406 : T maxvalue;
407 : T calibzero, calibmax;
408 : //
409 : for (casacore::Int i=1; i<ncontours; i++) {
410 : if (fn(T(i-1))>fn(T(i))) {
411 : throw(casacore::AipsError("ImageDecomposer<T>::autoContour-"
412 : " fn must be nondecreasing in domain"));
413 : }
414 : }
415 : //
416 : maxvalue = findAreaGlobalMax(casacore::IPosition(itsDim,0), shape());
417 : maxvalue -= (maxvalue-minvalue)/((ncontours-1)*10); //much closer to top
418 : calibzero = minvalue - fn(T(0));
419 : calibmax = (maxvalue - calibzero) / fn(ncontours - 1);
420 : //
421 : for (casacore::Int i=0; i<ncontours; i++) {
422 : contours(i) = calibzero + calibmax*fn(i);
423 : }
424 : //
425 : return contours;
426 : }
427 :
428 : template <class T>
429 0 : casacore::Matrix<T> ImageDecomposer<T>::componentList() const
430 : {
431 : //IMPR: the pixel->world conversion shouldn't have to be done every time.
432 :
433 0 : casacore::Matrix<T> worldList;
434 0 : worldList = itsList;
435 :
436 0 : for (casacore::uInt g = 0; g < itsNComponents; g++)
437 : {
438 0 : casacore::Vector<casacore::Double> centercoords(itsDim); //casacore::CoordinateSystem uses casacore::Double only
439 0 : casacore::Vector<casacore::Double> compwidth(itsDim);
440 0 : for (casacore::uInt d = 0; d < itsDim; d++)
441 : {
442 0 : centercoords(d) = itsList(g,1+d);
443 : }
444 0 : for (casacore::uInt d = 0; d < itsDim; d++)
445 : {
446 0 : compwidth(d) = itsList(g,1+itsDim+d);
447 : }
448 :
449 0 : itsImagePtr->coordinates().toWorld(centercoords, centercoords);
450 0 : itsImagePtr->coordinates().toWorld(compwidth, compwidth);
451 0 : itsImagePtr->coordinates().makeWorldRelative(compwidth);
452 :
453 0 : for (casacore::uInt d = 0; d < itsDim; d++)
454 : {
455 0 : worldList(g,1+d) = centercoords(d);
456 : }
457 0 : for (casacore::uInt d = 0; d < itsDim; d++)
458 : {
459 0 : if (itsDim == 2 && d == 1) continue; // 2d: axis ratio, not x-width
460 0 : worldList(g,1+itsDim+d) = compwidth(d);
461 : }
462 :
463 : }
464 :
465 0 : return worldList;
466 0 : }
467 :
468 : template <class T>
469 : void ImageDecomposer<T>::componentMap() const
470 : {
471 : // does nothing yet.
472 : return;
473 : }
474 :
475 :
476 :
477 :
478 : // Maxima functions
479 : // ----------------
480 :
481 : template <class T>
482 0 : T ImageDecomposer<T>::findAreaGlobalMax(casacore::IPosition blc, casacore::IPosition trc) const
483 : {
484 : T val;
485 0 : T maxval = 0.0;
486 0 : correctBlcTrc(blc,trc);
487 : //
488 : {
489 0 : casacore::IPosition pos(blc);
490 0 : decrement(pos);
491 0 : while (increment(pos,trc)) {
492 0 : val = getImageVal(pos);
493 0 : if (val > maxval) maxval = val;
494 : }
495 0 : }
496 : //
497 0 : return maxval;
498 : }
499 :
500 :
501 : template <class T>
502 : void ImageDecomposer<T>::findAreaGlobalMax(T& maxval, casacore::IPosition& maxvalpos,
503 : casacore::IPosition blc, casacore::IPosition trc) const
504 : {
505 : T val;
506 :
507 : maxvalpos = casacore::IPosition(itsDim,0);
508 : maxval = 0.0;
509 : correctBlcTrc (blc,trc);
510 : //
511 : {
512 : casacore::IPosition pos(blc); decrement(pos);
513 : while (increment(pos,trc)) {
514 : val = getImageVal(pos);
515 : if (val > maxval) {maxval = val; maxvalpos = pos;}
516 : }
517 : }
518 :
519 : }
520 :
521 : template <class T>
522 : casacore::Vector<T> ImageDecomposer<T>::findAreaLocalMax(casacore::IPosition blc, casacore::IPosition trc,
523 : casacore::Int naxis) const
524 : {
525 : casacore::uInt const blocksize = 10;
526 : casacore::uInt maxn = 0;
527 : casacore::Vector<T> maxvals;
528 : correctBlcTrc (blc, trc);
529 : //
530 : {
531 : casacore::IPosition pos(blc);
532 : decrement(pos);
533 : while (increment(pos,trc)) {
534 : if (isLocalMax(pos,naxis)) {
535 : if (maxn % blocksize == 0) {
536 : maxvals.resize(maxn+blocksize, true);
537 : }
538 : maxvals(maxn) = getImageVal(pos);
539 : maxn++;
540 : }
541 : }
542 : }
543 : maxvals.resize(maxn, true);
544 : return maxvals;
545 : }
546 :
547 :
548 : template <class T>
549 : void ImageDecomposer<T>::findAreaLocalMax(casacore::Vector<T>& maxvals,
550 : casacore::Block<casacore::IPosition>& maxvalpos,
551 : casacore::IPosition blc, casacore::IPosition trc,
552 : casacore::Int naxis) const
553 : {
554 : casacore::uInt const blocksize = 10;
555 : casacore::uInt maxn = 0;
556 : maxvals.resize();
557 : maxvalpos.resize(0);
558 : correctBlcTrc(blc, trc);
559 : //
560 : {
561 : casacore::IPosition pos(blc);
562 : decrement(pos);
563 : while (increment(pos,trc)) {
564 : if (isLocalMax(pos,naxis)) {
565 : if (maxn % blocksize == 0) {
566 : maxvals.resize(maxn+blocksize, true);
567 : maxvalpos.resize(maxn+blocksize, false, true);
568 : }
569 : maxvals(maxn) = getImageVal(pos);
570 : maxvalpos[maxn] = pos;
571 : maxn++;
572 : }
573 : }
574 : }
575 : maxvals.resize(maxn, true);
576 : maxvalpos.resize(maxn, true, true);
577 : return;
578 : }
579 :
580 :
581 :
582 : template <class T>
583 : casacore::Vector<T> ImageDecomposer<T>::findRegionLocalMax(casacore::Int regionID, casacore::Int naxis) const
584 : {
585 : casacore::uInt const blocksize = 10;
586 : casacore::uInt maxn = 0;
587 : casacore::Vector<T> maxvals;
588 : {
589 : casacore::IPosition pos(itsDim,0);
590 : decrement(pos);
591 : while (increment(pos,shape())) {
592 : if ((getCell(pos) == regionID) && isLocalMax(pos,naxis)) {
593 : if (maxn % blocksize == 0) {
594 : maxvals.resize(maxn+blocksize, true);
595 : }
596 : maxvals(maxn) = getImageVal(pos);
597 : maxn++;
598 : }
599 : }
600 : }
601 : maxvals.resize(maxn, true);
602 : return maxvals;
603 : }
604 :
605 :
606 : template <class T>
607 0 : void ImageDecomposer<T>::findRegionLocalMax(casacore::Vector<T>& maxvals,
608 : casacore::Block<casacore::IPosition>& maxvalpos,
609 : casacore::Int regionID, casacore::Int naxis) const
610 : {
611 0 : casacore::uInt const blocksize = 10;
612 0 : casacore::uInt maxn = 0;
613 0 : maxvals.resize();
614 0 : maxvalpos.resize(0);
615 : //
616 : {
617 0 : casacore::IPosition pos(itsDim,0);
618 0 : decrement(pos);
619 0 : while (increment(pos,shape())) {
620 0 : if ((getCell(pos) == regionID) && isLocalMax(pos,naxis)) {
621 0 : cout << "Local max at " << pos << endl;
622 0 : if (maxn % blocksize == 0) {
623 0 : maxvals.resize(maxn+blocksize, true);
624 0 : maxvalpos.resize(maxn+blocksize, false, true);
625 : }
626 0 : maxvals(maxn) = getImageVal(pos);
627 0 : maxvalpos[maxn] = pos;
628 0 : maxn++;
629 : }
630 : }
631 0 : }
632 : //
633 0 : maxvals.resize(maxn, true);
634 0 : maxvalpos.resize(maxn, true, true);
635 : //
636 0 : return;
637 : }
638 :
639 : template <class T>
640 0 : casacore::Vector<T> ImageDecomposer<T>::findAllRegionGlobalMax() const
641 : {
642 : //NOTE: while the regions are identified in the itsMapPtr with #s starting at
643 : //one, the array returned by this function begin with zero, so there is
644 : //an offset of one between itsMapPtr IDs and those used by this function.
645 :
646 : casacore::Int r;
647 : T val;
648 0 : casacore::Vector<T> maxval(itsNRegions);
649 0 : maxval = 0.0;
650 : //
651 : {
652 0 : casacore::IPosition pos(itsDim,0);
653 0 : decrement(pos);
654 0 : while (increment(pos,shape())) {
655 0 : r = getCell(pos);
656 0 : if (r > 0) {
657 0 : val = getImageVal(pos);
658 0 : if (val > maxval(r-1)) maxval(r-1) = val;
659 : }
660 : }
661 0 : }
662 0 : return maxval;
663 0 : }
664 :
665 : template <class T>
666 0 : void ImageDecomposer<T>::findAllRegionGlobalMax(casacore::Vector<T>& maxvals,
667 : casacore::Block<casacore::IPosition>& maxvalpos) const
668 : {
669 : //NOTE: while the regions are identified in the itsMapPtr with #s starting at
670 : //one, the arrays returned by this function begin with zero, so there is
671 : //an offset of one between itsMapPtr IDs and those used by this function.
672 :
673 : casacore::Int r;
674 : T val;
675 :
676 0 : maxvals.resize(itsNRegions);
677 0 : maxvalpos.resize(itsNRegions);
678 0 : maxvals = 0; //note: wholly negative images still return 0
679 :
680 : {
681 0 : casacore::IPosition pos(itsDim,0);
682 0 : decrement(pos);
683 0 : while (increment(pos,shape())) {
684 0 : r = getCell(pos);
685 0 : if (r > 0) {
686 0 : val = getImageVal(pos);
687 0 : if (val > maxvals(r-1)) {
688 0 : maxvals(r-1) = val;
689 0 : maxvalpos[r-1] = pos;
690 : }
691 : }
692 : }
693 0 : }
694 :
695 0 : return;
696 : }
697 :
698 :
699 : template <class T>
700 0 : bool ImageDecomposer<T>::isLocalMax(const casacore::IPosition& pos, casacore::Int naxis) const
701 : {
702 0 : if (pos.nelements()==2) {
703 0 : return isLocalMax(pos(0), pos(1), naxis);
704 0 : } else if (pos.nelements()==3) {
705 0 : return isLocalMax(pos(0), pos(1), pos(2),naxis);
706 : } else {
707 0 : throw(casacore::AipsError("ImageDecomposer<T>::localmax(IPosition pos, Int naxis)"
708 : " - pos has wrong number of dimensions"));
709 : }
710 : return false;
711 : }
712 :
713 : template <class T>
714 0 : bool ImageDecomposer<T>::isLocalMax(casacore::Int x, casacore::Int y, casacore::Int naxis) const
715 : {
716 0 : T val = getImageVal(x,y);
717 0 : casacore::Int ximin = (x>0)? -1:0;
718 0 : casacore::Int yimin = (y>0)? -1:0;
719 0 : casacore::Int ximax = (x+1<shape(0))? 1:0;
720 0 : casacore::Int yimax = (y+1<shape(1))? 1:0;
721 0 : for (casacore::Int xi=ximin; xi<=ximax; xi++) {
722 0 : for (casacore::Int yi=yimin; yi<=yimax; yi++) {
723 0 : if ( ((naxis > 0) || !(xi || yi))
724 0 : && ((naxis > 1) || !(xi && yi))
725 0 : && (getImageVal(x+xi,y+yi) > val)) {
726 0 : return false;
727 : }
728 : }
729 : }
730 : //
731 0 : return true;
732 : }
733 :
734 : template <class T>
735 0 : bool ImageDecomposer<T>::isLocalMax(casacore::Int x, casacore::Int y, casacore::Int z, casacore::Int naxis) const
736 : {
737 0 : T maxval = getImageVal(x,y,z);
738 0 : casacore::Int ximin = (x>0)? -1:0;
739 0 : casacore::Int yimin = (y>0)? -1:0;
740 0 : casacore::Int zimin = (z>0)? -1:0;
741 0 : casacore::Int ximax = (x+1<shape(0))? 1:0;
742 0 : casacore::Int yimax = (y+1<shape(1))? 1:0;
743 0 : casacore::Int zimax = (z+1<shape(2))? 1:0;
744 0 : for (casacore::Int xi=ximin; xi<=ximax; xi++) {
745 0 : for (casacore::Int yi=yimin; yi<=yimax; yi++) {
746 0 : for (casacore::Int zi=zimin; zi<=zimax; zi++) {
747 0 : if ( ((naxis > 0) || !(xi || yi || zi))
748 0 : && ((naxis > 1) || !((xi && yi) || (xi && zi) || (yi && zi) ))
749 0 : && ((naxis > 2) || !(xi && yi && zi))
750 0 : && (getImageVal(x+xi,y+yi,z+zi) > maxval)) {
751 0 : return false;
752 : }
753 : }
754 : }
755 : }
756 : //
757 0 : return true;
758 : }
759 :
760 :
761 : // Estimation Functions
762 : // --------------------
763 :
764 :
765 : template <class T>
766 0 : void ImageDecomposer<T>::estimateComponentWidths(casacore::Matrix<T>& width,
767 : const casacore::Block<casacore::IPosition>& maxvalpos)
768 : const
769 : {
770 : // Finds a rough estimate of the width of each component.
771 : // Requires the location of each component.
772 :
773 : // This function is now mostly obsolete; its functionality replaced by
774 : // calculateMoments() except on non-deblended images.
775 :
776 0 : width.resize(maxvalpos.nelements(), itsDim);
777 : casacore::Bool dblflag;
778 : //
779 0 : for (casacore::uInt r = 0; r < maxvalpos.nelements(); r++) {
780 0 : casacore::IPosition lpos(itsDim);
781 0 : casacore::IPosition rpos(itsDim);
782 0 : casacore::IPosition maxpos(itsDim);
783 0 : maxpos = maxvalpos[r];
784 0 : T maxvalr = getImageVal(maxpos);
785 0 : T thrval = maxvalr*0.25;
786 : T val, prevval;
787 0 : for (casacore::uInt a = 0; a < itsDim; a++) {
788 0 : dblflag = 0;
789 0 : lpos = maxpos;
790 0 : val = maxvalr;
791 0 : prevval = val;
792 0 : while ((lpos(a) > 0) && (val >= thrval) && (val <= prevval)) {
793 0 : prevval = val;
794 0 : lpos(a) --;
795 0 : val = getImageVal(lpos);
796 : }
797 0 : if (val < thrval) {
798 0 : width(r,a) = T(maxpos(a)-lpos(a)) - (thrval-val) / (prevval-val);
799 0 : } else if (val > prevval) {
800 0 : width(r,a) = T(maxpos(a)-lpos(a));
801 : } else { //lpos == 0
802 0 : {width(r,a) = 0; dblflag = 1;} //can't find left limit;
803 : //use 2xright limit instead
804 : }
805 :
806 0 : rpos = maxpos;
807 0 : val = maxvalr;
808 0 : prevval = val;
809 0 : while ((rpos(a)<shape(a)-1) && (val >= thrval) && (val <= prevval)) {
810 0 : prevval = val;
811 0 : rpos(a) ++;
812 0 : val = getImageVal(rpos);
813 : }
814 0 : if (val < thrval) {
815 0 : width(r,a) += T(rpos(a)-maxpos(a)) - (thrval-val) / (prevval-val);
816 0 : } else if (val > prevval) {
817 0 : width(r,a) += T(rpos(a)-maxpos(a));
818 : } else {
819 0 : if (!dblflag) {
820 0 : dblflag = 1; //use 2x left side instead
821 : } else {
822 0 : width(r,a) += T(rpos(a)-maxpos(a)) * (maxvalr-thrval)/(maxvalr-val);
823 0 : dblflag = 1;
824 : }
825 : }
826 : //
827 0 : if (width(r,a) <= 0.0) width(r,a) = shape(a);//gaussian bigger than image
828 0 : if (!dblflag) width(r,a) /= 2.0;
829 0 : if (casacore::isNaN(width(r,a)))
830 : {
831 0 : width(r,a) = 1.0;
832 0 : cerr << "WARNING: Nonphysical estimate, setting width to 1.0" << endl;
833 : }
834 :
835 : }
836 : }
837 : //
838 0 : return;
839 : }
840 :
841 : template <class T>
842 0 : casacore::Array<T> ImageDecomposer<T>::calculateMoments(casacore::Int region) const
843 : {
844 : // Calculates the moments of an image region up to second order.
845 :
846 : // The current implementation is inefficient because it must scan the entire
847 : // image for each region. It would be better to return an array of Arrays,
848 : // or a casacore::Matrix with the M array collapsed to 1D and the region # along the
849 : // other axis.
850 :
851 0 : casacore::IPosition pos(itsDim);
852 0 : casacore::IPosition start(itsDim,0);
853 0 : decrement(start);
854 : T I;
855 :
856 0 : if (itsDim == 2)
857 : {
858 0 : casacore::Matrix<T> M(3,3, 0.0);
859 0 : pos = start;
860 0 : while (increment(pos,shape())) {
861 0 : if (getCell(pos) == region)
862 : {
863 0 : I = getImageVal(pos);
864 0 : M(0,0) += I;
865 0 : M(1,0) += pos(0) * I;
866 0 : M(0,1) += pos(1) * I;
867 : }
868 : }
869 :
870 :
871 0 : T xc = M(1,0) / M(0,0);
872 0 : T yc = M(0,1) / M(0,0);
873 :
874 0 : pos = start;
875 0 : while (increment(pos,shape())) {
876 0 : if (getCell(pos) == region)
877 : {
878 0 : I = getImageVal(pos);
879 0 : T xd = pos(0) - xc;
880 0 : T yd = pos(1) - yc;
881 0 : M(1,1) += xd * yd * I;
882 0 : M(2,0) += xd * xd * I;
883 0 : M(0,2) += yd * yd * I;
884 : }
885 : }
886 :
887 0 : return M;
888 : //Does not calculate higher level components (2,1; 1,2; 2,2)
889 0 : }
890 :
891 0 : if (itsDim == 3)
892 : {
893 0 : casacore::Cube<T> M(3,3,3, 0.0);
894 :
895 0 : pos = start;
896 0 : while (increment(pos,shape())) {
897 0 : if (getCell(pos) == region)
898 : {
899 0 : I = getImageVal(pos);
900 0 : M(0,0,0) += I;
901 0 : M(1,0,0) += pos(0) * I;
902 0 : M(0,1,0) += pos(1) * I;
903 0 : M(0,0,1) += pos(2) * I;
904 : }
905 : }
906 :
907 :
908 0 : T xc = M(1,0,0) / M(0,0,0);
909 0 : T yc = M(0,1,0) / M(0,0,0);
910 0 : T zc = M(0,0,1) / M(0,0,0);
911 0 : pos = start;
912 0 : while (increment(pos,shape())) {
913 0 : if (getCell(pos) == region)
914 : {
915 0 : I = getImageVal(pos);
916 0 : T xd = pos(0) - xc;
917 0 : T yd = pos(1) - yc;
918 0 : T zd = pos(2) - zc;
919 0 : M(1,1,0) += xd * yd * I;
920 0 : M(1,0,1) += xd * zd * I;
921 0 : M(0,1,1) += yd * zd * I;
922 0 : M(2,0,0) += xd * xd * I;
923 0 : M(0,2,0) += yd * yd * I;
924 0 : M(0,0,2) += zd * zd * I;
925 : }
926 : }
927 :
928 0 : return M;
929 0 : }
930 :
931 0 : return casacore::Array<T>();
932 0 : }
933 :
934 :
935 : // Region editing functions
936 : // ------------------------
937 :
938 : template <class T>
939 0 : void ImageDecomposer<T>::boundRegions(casacore::Block<casacore::IPosition>& blc,
940 : casacore::Block<casacore::IPosition>& trc)
941 : {
942 : // Boxes each region in the componentmap:
943 : // blc is set to the lowest coordinate value in each region;
944 : // trc is set to one above the highest coordinate value in each region.
945 :
946 0 : DebugAssert(blc.nelements() == itsNRegions, casacore::AipsError);
947 0 : DebugAssert(trc.nelements() == itsNRegions, casacore::AipsError);
948 :
949 0 : for (casacore::uInt r=0; r<itsNRegions; r++) {
950 0 : blc[r] = itsShape;
951 0 : trc[r] = casacore::IPosition(itsDim,0);
952 : }
953 :
954 : {
955 0 : casacore::IPosition pos(itsDim,0);
956 0 : decrement(pos);
957 : casacore::Int r;
958 0 : while (increment(pos,shape())) {
959 0 : r = getCell(pos);
960 0 : if (r > 0) {
961 0 : for (casacore::uInt i = 0; i < itsDim; i++) {
962 0 : if (blc[r-1](i) > pos(i)) blc[r-1](i) = pos(i);
963 0 : if (trc[r-1](i) <= pos(i)) trc[r-1](i) = pos(i)+1;
964 : }
965 : }
966 : }
967 0 : }
968 :
969 0 : return;
970 : }
971 :
972 : template <class T>
973 0 : void ImageDecomposer<T>::zero()
974 : {
975 : // Set all elements in the component map to zero and clear the component list.
976 :
977 0 : itsMapPtr->set(0);
978 0 : itsNRegions = 0;
979 0 : itsNComponents = 0;
980 0 : itsList.resize();
981 0 : return;
982 : }
983 :
984 : template <class T>
985 0 : void ImageDecomposer<T>::clear()
986 : {
987 : //Clear the component map
988 0 : casacore::LatticeIterator<casacore::Int> iter(*itsMapPtr);
989 : casacore::Bool deleteIt;
990 0 : casacore::Int* p = 0;
991 0 : for (iter.reset(); !iter.atEnd(); iter++) {
992 0 : casacore::Array<casacore::Int>& tmp = iter.rwCursor();
993 0 : p = tmp.getStorage(deleteIt);
994 0 : for (casacore::uInt i=0; i<tmp.nelements(); i++) if (p[i] != MASKED) p[i] = 0;
995 0 : tmp.putStorage(p, deleteIt);
996 : }
997 0 : itsNRegions = 0;
998 :
999 : //Clear the component list
1000 0 : itsNComponents = 0;
1001 0 : itsList.resize();
1002 0 : return;
1003 0 : }
1004 :
1005 :
1006 : template <class T>
1007 0 : void ImageDecomposer<T>::destroyRegions(const casacore::Vector<casacore::Bool>& killRegion)
1008 : {
1009 : //Wipes out any regions whose corresponding values in killRegion are true
1010 : // by setting all pixel values in the componentmap set to that region to
1011 : // zero. Zero-oriented; there is an offset of one between the index in
1012 : // killRegion and the actual region in the componentmap.
1013 :
1014 : {
1015 0 : casacore::IPosition pos(itsDim,0); decrement(pos);
1016 0 : while (increment(pos,shape()))
1017 : {
1018 0 : casacore::Int reg = getCell(pos);
1019 0 : if (reg > 0 && killRegion(reg-1)) setCell(pos,0);
1020 : }
1021 0 : }
1022 :
1023 0 : renumberRegions();
1024 0 : return;
1025 : }
1026 :
1027 :
1028 : template <class T>
1029 0 : void ImageDecomposer<T>::renumberRegions()
1030 : {
1031 : //Eliminates redundant regions (components with no representative cells in
1032 : //the component map) by renumbering higher-numbered regions to fill in
1033 : //the gaps. For example..
1034 : // 011 011
1035 : // 113 becomes 112
1036 : // 113 112
1037 :
1038 0 : casacore::Vector<casacore::Bool> regpresent(itsNRegions+1, 0);
1039 0 : casacore::Vector<casacore::Int> renumregs(itsNRegions+1);
1040 0 : casacore::uInt const ngpar = itsDim * 3;
1041 :
1042 : //any region that has any pixel members is flagged as 1, others left 0
1043 :
1044 : {
1045 0 : casacore::IPosition pos(itsDim,0); decrement(pos);
1046 0 : while (increment(pos,shape()))
1047 : {
1048 0 : casacore::Int reg = getCell(pos);
1049 0 : if (reg >= 0) regpresent(reg) = 1;
1050 : }
1051 0 : }
1052 :
1053 : //determine new # of regions and which regions will be renumbered to what
1054 0 : casacore::uInt newnr = 0;
1055 0 : for (casacore::uInt r = 1; r <= itsNRegions; r++)
1056 0 : if (regpresent(r)) renumregs(r) = ++newnr;
1057 :
1058 0 : if (newnr < itsNRegions)
1059 : {
1060 0 : itsNRegions = newnr;
1061 :
1062 : //actually renumber the regions in the pmap
1063 : {
1064 0 : casacore::IPosition pos(itsDim,0); decrement(pos);
1065 0 : while (increment(pos,shape()))
1066 : {
1067 0 : casacore::Int reg = getCell(pos);
1068 0 : if (reg >= 0) setCell(pos, renumregs(reg));
1069 : }
1070 0 : }
1071 :
1072 0 : if (isDecomposed())
1073 : {
1074 : //eliminate componentlist entries of lost components
1075 0 : casacore::Matrix<T> oldcomponentlist(itsList);
1076 :
1077 0 : itsList.resize(newnr, ngpar);
1078 0 : for (casacore::Int c = 0; c < casacore::Int(itsNComponents); c++)
1079 0 : if (regpresent(c+1) && (c+1 != renumregs(c+1)))
1080 0 : for (casacore::uInt p = 0; p < 9; p++)
1081 0 : itsList(renumregs(c+1)-1,p) = oldcomponentlist(c+1,p);
1082 :
1083 0 : itsNComponents = newnr;
1084 0 : }
1085 : }
1086 :
1087 0 : return;
1088 0 : }
1089 :
1090 : template <class T>
1091 0 : void ImageDecomposer<T>::synthesize(const ImageDecomposer<T>& subdecomposer,
1092 : casacore::IPosition blc)
1093 : {
1094 : // Overlays a smaller map onto an empty region of a larger map,
1095 : // and adds submap component list to main component list.
1096 :
1097 : // The user should exercise caution with this function and synthesize submaps
1098 : // only into regions of the main map that are truly empty (0), because the
1099 : // program does not perform any blending between components.
1100 : // Otherwise, false detections are likely.
1101 :
1102 0 : casacore::uInt ngpar = 0;
1103 0 : if (itsDim == 2) ngpar = 6;
1104 0 : if (itsDim == 3) ngpar = 9;
1105 :
1106 : // Scan to the edge of the boundary of the host map or the submap, whichever
1107 : // is closer.
1108 :
1109 0 : casacore::IPosition scanlimit(itsDim); //submap-indexed
1110 0 : for (casacore::uInt i=0; i<itsDim; i++) {
1111 0 : if (subdecomposer.shape(i) > shape(i) - blc(i)) {
1112 0 : scanlimit(i) = shape(i) - blc(i);
1113 : } else {
1114 0 : scanlimit(i) = subdecomposer.shape(i);
1115 : }
1116 : }
1117 :
1118 : // Write pixels in sub- component map to main component map.
1119 :
1120 : {
1121 0 : casacore::IPosition pos(itsDim,0); //submap-indexed
1122 0 : decrement(pos);
1123 0 : while (increment(pos,scanlimit)) {
1124 0 : if (subdecomposer.getCell(pos) > 0) {
1125 0 : setCell(pos + blc, itsNRegions + subdecomposer.getCell(pos));
1126 : }
1127 : }
1128 0 : }
1129 0 : itsNRegions += subdecomposer.numRegions();
1130 :
1131 : // Add components in subdecomposer to components in main decomposer.
1132 :
1133 0 : if (subdecomposer.isDecomposed()) {
1134 :
1135 0 : casacore::Matrix<T> oldList;
1136 0 : oldList = itsList;
1137 0 : itsList.resize(itsNComponents+subdecomposer.numComponents(),ngpar);
1138 0 : for (casacore::uInt c = 0; c < itsNComponents; c++) {
1139 0 : for (casacore::uInt p = 0; p < ngpar; p++) {
1140 0 : itsList(c,p) = oldList(c,p); //copy after resize
1141 : }
1142 : }
1143 :
1144 0 : for (casacore::uInt subc = 0; subc < subdecomposer.numComponents(); subc++) {
1145 0 : for (casacore::uInt p = 0; p < ngpar; p++) {
1146 0 : itsList(itsNComponents+subc,p)=subdecomposer.itsList(subc,p);
1147 : }
1148 : // make adjustments to center values due to offset
1149 0 : if (itsDim == 2) {
1150 0 : itsList(itsNComponents+subc,1) += blc(0);
1151 0 : itsList(itsNComponents+subc,2) += blc(1);
1152 0 : } else if (itsDim == 3) {
1153 0 : itsList(itsNComponents+subc,1) += blc(0);
1154 0 : itsList(itsNComponents+subc,2) += blc(1);
1155 0 : itsList(itsNComponents+subc,3) += blc(2);
1156 : }
1157 : }
1158 0 : itsNComponents += subdecomposer.numComponents();
1159 :
1160 0 : }
1161 : //
1162 : //renumberRegions(); //this should have no effect unless this function
1163 : //was used to overwrite an entire region, which
1164 : //should be avoided.
1165 0 : }
1166 :
1167 :
1168 :
1169 : // Analysis functions
1170 : // ------------------
1171 :
1172 :
1173 : template <class T>
1174 0 : casacore::uInt ImageDecomposer<T>::identifyRegions(T thrval, casacore::Int naxis)
1175 : {
1176 : // Performs a single threshold scan on the image. In other words,
1177 : // identifies all contigous blocks of pixels in the target image above the
1178 : // threshold value thrval, assigning each unique block to an integer,
1179 : // starting at one. All pixels with target image values below thrval are set
1180 : // to zero.
1181 :
1182 : // NOTE: Formerly a specialization existed for 2D which may have been slightly
1183 : // more efficient. However, it complicated the code excessively (this
1184 : // program is already far too long.) It could be resurrected if necessary.
1185 :
1186 0 : casacore::Int const blocksize = 1024; //increment to grow size of anchor array
1187 0 : casacore::Int const pageexpsize = 128;
1188 0 : casacore::Int cnum = 0; //region number
1189 0 : if (naxis > casacore::Int(itsDim)) naxis = itsDim;
1190 :
1191 : // The program first scans through the image until it finds any pixel in
1192 : // any region. Once there, it immediately scans all 6 adjacent pixels,
1193 : // registering any that fall within the region and setting them as anchors.
1194 : // It then moves to the first of these anchors and repeats the process,
1195 : // until no more anchors can be found and every existing anchor has already
1196 : // been explored. It then scans until it locates a new region, and repeats
1197 : // until every region has been similarly scanned.
1198 :
1199 : // This has the equivalent effect of a 'surface' of active anchors
1200 : // sweeping across each region starting at a seed point until the
1201 : // region is fully explored.
1202 :
1203 : // The naxis parameter must be 2 or greater to avoid spurious detections
1204 : // along horizontal ridges. However, this slows down performance by a factor
1205 : // of roughly two, so in instances where objects are clearly defined and
1206 : // not closely blended and the image is very large naxis=1 may be better.
1207 :
1208 0 : casacore::IPosition scanpos(itsDim,0); //decrement(scanpos);
1209 0 : while (true) {
1210 : //First find any pixel in next region.
1211 : //Stop scanning when an unassigned, unmasked pixel is found exceeding
1212 : //the threshold value.
1213 :
1214 0 : while (getImageVal(scanpos) < thrval || getCell(scanpos)) {
1215 0 : if (!increment(scanpos,shape())) {
1216 0 : return itsNRegions = cnum;
1217 : }
1218 : //scanned w/out finding new region
1219 : }
1220 : //
1221 0 : casacore::IPosition pos(scanpos);
1222 0 : cnum++;
1223 :
1224 : // As many anchors will be required as pixels in the region (the volume) -
1225 : // but only a small fraction of that at any one time (the active surface).
1226 : // So the program allocates 'pages' of anchors as they become necessary,
1227 : // but continually deletes pages of anchors that have already been used.
1228 :
1229 0 : casacore::Int seta = -1; //index of highest established anchor
1230 0 : casacore::Int geta = -1; //index of highest analyzed anchor
1231 : //the active surface is all anchors geta < a < seta
1232 0 : casacore::PtrBlock<casacore::Matrix<casacore::Int> *> aindex(pageexpsize); //anchor structure
1233 0 : casacore::Int setblock = -1; //index of page containing highest established anchor
1234 0 : casacore::Int getblock = -1; //index of page containing highest analyzed anchor
1235 0 : setCell(pos,cnum);
1236 :
1237 : do { //(geta < seta)
1238 : //cout << geta << " / " << seta << ", " << pos <<
1239 : // " = " << getCell(pos) << endl;
1240 :
1241 : //Analyze the cell -
1242 : //Scan the cells around the active cell as follows:
1243 : //naxis = 1: scan 6 adjacent cells (axes only)
1244 : //naxis = 2: scan 18 adjacent cells (axes and 2-axis diagonals)
1245 : //naxis = 3: scan 26 adjacent cells (axes and 2/3-axis diagonals)
1246 :
1247 0 : casacore::Int ximin = (pos(0)>0)? -1:0;
1248 0 : casacore::Int yimin = (pos(1)>0)? -1:0;
1249 0 : casacore::Int zimin = ((itsDim>=3)&&(pos(2)>0))? -1:0;
1250 0 : casacore::Int ximax = (pos(0)+1<shape(0))? 1:0;
1251 0 : casacore::Int yimax = (pos(1)+1<shape(1))? 1:0;
1252 0 : casacore::Int zimax = ((itsDim>=3)&&(pos(2)+1<shape(2)))? 1:0; //safe for 2D
1253 : //
1254 0 : for (casacore::Int xi=ximin; xi<=ximax; xi++) {
1255 0 : for (casacore::Int yi=yimin; yi<=yimax; yi++) {
1256 0 : for (casacore::Int zi=zimin; zi<=zimax; zi++) {
1257 0 : if ( (xi || yi || zi) &&
1258 0 : ((naxis > 1) || !((xi && yi) || (xi && zi) || (yi && zi) )) &&
1259 0 : ((naxis > 2) || !(xi && yi && zi))) {
1260 0 : casacore::IPosition ipos(pos);
1261 0 : ipos(0) += xi; ipos(1) += yi; if (itsDim == 3) ipos(2) += zi;
1262 :
1263 : //if any contiguous pixel is
1264 0 : if ((getImageVal(ipos) >= thrval) // above threshold and
1265 0 : && getCell(ipos) != cnum) { // not yet scanned...
1266 : //record its location as an anchor and come back later.
1267 0 : seta++;
1268 :
1269 0 : if ((seta % blocksize) == 0) {
1270 :
1271 : //current block out of memory: allocate new memory block
1272 :
1273 0 : setblock++;
1274 0 : if ((setblock % pageexpsize == 0) && setblock) {
1275 0 : aindex.resize(((setblock/pageexpsize)+1)*pageexpsize);
1276 : }
1277 0 : aindex[setblock] = new casacore::Matrix<casacore::Int>(blocksize,itsDim);
1278 : }
1279 :
1280 : //set new anchor
1281 0 : for (casacore::uInt axis = 0; axis < itsDim; axis ++) {
1282 0 : (*(aindex[setblock]))(seta%blocksize,axis) = ipos(axis);
1283 : }
1284 :
1285 : //cout<<'A'<<seta<<'['<<x+xi<<','<<y+yi<<','<<z+zi<<']'<<endl;
1286 :
1287 0 : setCell(ipos, cnum);
1288 : }
1289 0 : }
1290 : }
1291 : }
1292 : }
1293 0 : geta++;
1294 :
1295 :
1296 0 : if (((geta % blocksize) == 0) || (geta>seta)) {
1297 0 : if (getblock>=0) {
1298 : //memory block data obsolete: delete old memory block
1299 0 : delete aindex[getblock];
1300 : }
1301 0 : getblock++;
1302 : }
1303 :
1304 0 : if (geta <= seta) {
1305 : //go to lowest anchor
1306 0 : for (casacore::uInt axis = 0; axis < itsDim; axis++) {
1307 0 : pos(axis) = (*(aindex[getblock]))(geta%blocksize,axis);
1308 : }
1309 : //cout << ">>A" << geta << " " << endl;
1310 : }
1311 :
1312 0 : } while (geta <= seta);
1313 : }
1314 0 : }
1315 :
1316 : template <class T>
1317 0 : void ImageDecomposer<T>::deblendRegions(const casacore::Vector<T>& contours,
1318 : casacore::Int minRange, casacore::Int naxis)
1319 : {
1320 :
1321 : // Performs the contour decomposition on a blended image to generate a
1322 : // component map that can detect components blended above any threshold(s),
1323 : // by performing threshold scans at each contour level and recognizing
1324 : // as individual any components that are distinct above any such level.
1325 :
1326 0 : casacore::Int const printIntermediates = 0;
1327 0 : casacore::Int const blocksize = 3;
1328 0 : casacore::Int ncontours = contours.nelements();
1329 :
1330 0 : ImageDecomposer<T> contourMap(*this);//Component map thresholded at current
1331 : //contour level; "lower" contour
1332 0 : casacore::Block<casacore::IPosition> regcenter; //Coordinates of first pixel found in each
1333 : //component (a rough estimate of the center)
1334 : //Indexing for this array is offset by one.
1335 0 : casacore::Vector<casacore::Int> originlevel; //first contour in which region was detected
1336 : //Indexing for this array is offset by one.
1337 : //If set to -1 the region is defunct.
1338 :
1339 :
1340 0 : if (isDerived()) zero();
1341 :
1342 : // Component decomposition:
1343 : // This is the main deblending algorithm. The program starts by performing
1344 : // a threshold scan at the top contour value, separating any regions
1345 : // that are visibly distinct at that threshold. It continues downward though
1346 : // the contour vector, forming a component map from each contour and comparing
1347 : // that with the contour map that is gradually forming to distinguish new
1348 : // regions, correspondent regions, and blending regions, and assigns the
1349 : // pixels in the main itsMapPtr based on this information.
1350 :
1351 0 : for (casacore::Int c = ncontours-1; c >= 0; c--) {
1352 : if (printIntermediates == 2) cout << endl << "CONTOUR " << c << endl;
1353 :
1354 : casacore::Int lowreg, highreg; //number of regions in lower contour, current pmap
1355 0 : contourMap.clear(); //only necessary if region grows between contours
1356 :
1357 0 : lowreg = contourMap.identifyRegions(contours(c),naxis);
1358 0 : highreg = itsNRegions;
1359 :
1360 : if (printIntermediates) {
1361 : cout << "Now comparing current pmap to contour " << c << '.' << endl;
1362 : display();
1363 : contourMap.display();
1364 : }
1365 :
1366 0 : casacore::Vector<casacore::Int> root(highreg+1, 0); //Indicates corresponding object
1367 : // in lower contour
1368 0 : casacore::Vector<casacore::Int> nOffspring(lowreg+1, 0); //Total number of different objects
1369 : // above this region
1370 0 : casacore::Block<casacore::Vector<casacore::Int>*> offspring(lowreg+1); //Region IDs of objects above
1371 : // this region
1372 :
1373 : // Can't finish allocation until nOffspring is known.
1374 :
1375 : // Scan through current pmap ("higher contour") and find the root of all
1376 : // regions as defined in the lower contour. Simultaneously mark all
1377 : // regions in the lower contour that have "offspring" above.
1378 :
1379 0 : for (casacore::Int r = 1; r <= highreg; r++) {
1380 0 : casacore::IPosition pos(itsDim,0); decrement(pos);
1381 0 : while (increment(pos,shape()) && !root(r)){
1382 0 : if (getCell(pos) == r) {
1383 0 : root(r) = contourMap.getCell(pos);
1384 0 : nOffspring(contourMap.getCell(pos)) += 1;
1385 : }
1386 : }
1387 : }
1388 :
1389 : // Set up offspring array
1390 :
1391 0 : for (casacore::Int r = 1; r <= lowreg; r++) {
1392 0 : offspring[r] = new casacore::Vector<casacore::Int>(nOffspring(r));
1393 : }
1394 :
1395 0 : for (casacore::Int lr = 1; lr <= lowreg; lr++) {
1396 0 : casacore::Int f = 0;
1397 0 : for (casacore::Int hr = 1; hr <= highreg; hr++) {
1398 0 : if (root(hr) == lr) (*offspring[lr])(f++) = hr;
1399 : }
1400 : }
1401 :
1402 : if (printIntermediates == 2) {
1403 : cout << "Contour Level " << c << endl;
1404 : cout << highreg << ' ' << lowreg << endl;
1405 :
1406 : for (casacore::Int hr = 1; hr <= highreg; hr++) {
1407 : cout << "root of " << hr << ':' << root(hr) << endl;
1408 : }
1409 :
1410 : for (casacore::Int lr = 1; lr <= lowreg; lr++) {
1411 : for (casacore::Int f = 0; f < nOffspring(lr); f++) {
1412 : cout << "offspring of " << lr << ':' << (*offspring[lr])(f) << endl;
1413 : }
1414 : }
1415 : }
1416 :
1417 :
1418 :
1419 : // If a newly discovered component merges with another too quickly
1420 : // (within minRange contours) rescind its status and treat it as part
1421 : // of the other contour.
1422 : // "f" refers somewhat cryptically to offspring index and "fr" to its
1423 : // region number in the pmap
1424 :
1425 0 : if (minRange > 1) {
1426 0 : for (casacore::Int lr = 1; lr <= lowreg; lr++) {
1427 0 : if (nOffspring(lr) > 1) {
1428 0 : for (casacore::Int f = 0; f < nOffspring(lr); f++) {
1429 0 : casacore::Int fr = (*offspring[lr])(f);
1430 :
1431 0 : if (originlevel(fr-1) - c < minRange)
1432 : {
1433 : //Find the closest offspring
1434 0 : casacore::Int mindistsq = 1073741823; //maximum casacore::Int value
1435 0 : casacore::Int frabs = 0; //closest region
1436 0 : for (casacore::Int f2 = 0; f2 < nOffspring(lr); f2++) {
1437 0 : if (f2 == f) continue;
1438 0 : casacore::Int fr2 = (*offspring[lr])(f2);
1439 0 : casacore::Int distsq = 0;
1440 0 : if (originlevel(fr2-1) == -1) continue;
1441 0 : for (casacore::uInt a = 0; a < itsDim; a++) {
1442 0 : distsq += casacore::square(casacore::Int(regcenter[fr2-1](a)-regcenter[fr-1](a)));
1443 : }
1444 0 : if (distsq < mindistsq) {
1445 0 : frabs = fr2;
1446 0 : mindistsq = distsq;
1447 : }
1448 : }
1449 0 : if (frabs == 0)
1450 : {
1451 : //No valid closest offspring - find biggest offspring
1452 0 : for (casacore::Int f2 = 0; f2 < nOffspring(lr); f2++) {
1453 0 : if (f2 == f) continue;
1454 0 : casacore::Int fr2 = (*offspring[lr])(f2);
1455 0 : casacore::Int maxlevel = 0;
1456 0 : if (originlevel(fr2-1) == -1) continue;
1457 0 : if (originlevel(fr2-1) > maxlevel) {
1458 0 : frabs = fr2;
1459 0 : maxlevel = originlevel(fr2-1);
1460 : }
1461 : }
1462 : }
1463 0 : if (frabs == 0)
1464 : {
1465 : //must be the only offspring left! Don't absorb.
1466 0 : break;
1467 : }
1468 :
1469 :
1470 : if (printIntermediates == 2) {
1471 : cout << "Absorbing region " << fr << " (origin at "
1472 : << originlevel(fr-1) << ") into region " << frabs << endl;
1473 : }
1474 0 : casacore::IPosition pos(itsDim,0); decrement(pos);
1475 0 : while (increment(pos,shape())){
1476 0 : if (getCell(pos) == fr) setCell(pos,frabs);
1477 : }
1478 0 : originlevel(fr-1) = -1;
1479 0 : }
1480 : }
1481 : }
1482 : }
1483 : }
1484 :
1485 : // Need to check if this works properly...
1486 :
1487 :
1488 :
1489 : // The object/region/component labeling is done in three steps to make the
1490 : // order most closely match the order in which they were found, and the
1491 : // order of the peak intensities.
1492 :
1493 : // First (and most complex) step is to deblend the large consolidated
1494 : // regions (nOffspring >= 2). The algorithm scans all pixels that
1495 : // exist in the new contour but not in the current pmap and belong to
1496 : // a region with multiple offspring, then scans the surrounding vicinity
1497 : // in the current pmap until it finds a pixel belonging to a region there,
1498 : // to which the new pixel is assigned.
1499 :
1500 0 : casacore::Int cgindex = 1; //component index base, global for this contour
1501 0 : ImageDecomposer<T> copyMap(*this); //The original data must be temporarily
1502 : //preserved while the componentmap is
1503 : //overwritten for comparisons between
1504 : //nearby pixels
1505 :
1506 0 : for (casacore::Int lr = 1; lr <= lowreg; lr++) {
1507 0 : if (nOffspring(lr) >= 2) {
1508 0 : casacore::IPosition pos(itsDim,0); decrement(pos);
1509 0 : while (increment(pos,shape())) {
1510 :
1511 : // Renumber pixels that already exist in the pmap
1512 0 : if ((contourMap.getCell(pos)==lr)&&(copyMap.getCell(pos))) {
1513 0 : for (casacore::Int f = 0; f < nOffspring(lr); f++) {
1514 :
1515 : // Translate old pmap id to new pmap id
1516 0 : if ((*offspring[lr])(f) == copyMap.getCell(pos))
1517 0 : setCell(pos, cgindex+f);
1518 : }
1519 : }
1520 :
1521 : // Number new pixels.
1522 :
1523 0 : if ((contourMap.getCell(pos)==lr)&&(!copyMap.getCell(pos))) {
1524 0 : casacore::Int pinh = 0; //region as defined in pmap pixel is set to
1525 0 : casacore::Int srad = 1; //search radius
1526 0 : casacore::uInt naxis = 1;
1527 :
1528 : // cout << "Searching for nearest cell to " << pos << endl;
1529 :
1530 0 : while(!pinh && srad < 250) { //search increasing naxis, srad
1531 : // IMPR: an N-dimensional structure would be better here.
1532 : casacore::Int xi, yi, zi;
1533 0 : casacore::Int ximin = (pos(0)-srad < 0)? -pos(0) : -srad;
1534 0 : casacore::Int ximax = (pos(0)+srad >= shape(0))? shape(0)-pos(0)-1 : srad;
1535 0 : casacore::Int yimin = (pos(1)-srad < 0)? -pos(1) : -srad;
1536 0 : casacore::Int yimax = (pos(1)+srad >= shape(1))? shape(1)-pos(1)-1 : srad;
1537 0 : casacore::Int zimin = 0, zimax = 0;
1538 0 : if (itsDim == 2) {
1539 0 : zimin = 0; zimax = 0;
1540 : }
1541 0 : if (itsDim >= 3) {
1542 0 : zimin = (pos(2)-srad < 0)? -pos(2) : -srad;
1543 0 : zimax = (pos(2)+srad >= shape(2))? shape(2)-pos(2)-1 : srad;
1544 : }
1545 0 : while (!pinh && naxis <= itsDim) {
1546 0 : for (xi = ximin; xi <= ximax; xi++) {
1547 0 : for (yi = yimin; yi <= yimax; yi++) {
1548 0 : for (zi = zimin; zi <= zimax; zi++) {
1549 0 : casacore::IPosition ipos(pos);
1550 0 : ipos(0) += xi; ipos(1) += yi;
1551 0 : if (itsDim==3) ipos(2) += zi;
1552 :
1553 0 : if (abs(xi)<srad && abs(yi)<srad && abs(zi)<srad) {
1554 0 : continue; //border of radius only
1555 : }
1556 :
1557 0 : if ( ((naxis==1) && ((xi&&yi) || (xi&&zi) || (yi&&zi)))
1558 0 : || ((naxis==2) && (xi && yi && zi))) {
1559 0 : continue;
1560 : }
1561 :
1562 0 : casacore::Int inh = copyMap.getCell(ipos);
1563 0 : if (inh<=0) continue;
1564 0 : if (!pinh) {
1565 0 : pinh = inh;
1566 0 : for (casacore::Int f = 0; f < nOffspring(lr); f++) {
1567 :
1568 : // Translate old pmap id to new pmap id
1569 :
1570 0 : if ((*offspring[lr])(f) == inh) {
1571 0 : setCell(pos, cgindex+f);
1572 : }
1573 : //reassign pixel to new component
1574 : }
1575 0 : } else if (pinh!=inh) {
1576 : //equidistant to different objects:
1577 : // temporarily flag as nonexistant object
1578 0 : setCell(pos, INDETERMINATE);
1579 : }
1580 : }
1581 : }
1582 : }
1583 0 : naxis++;
1584 : }
1585 0 : naxis = 1; srad++;
1586 : }
1587 : }
1588 : }
1589 0 : cgindex += nOffspring(lr);
1590 0 : }
1591 : }
1592 :
1593 : // Now scan nonforked regions that exist in both contours.
1594 : // This is as simple as just renumbering the region.
1595 :
1596 0 : for (casacore::Int lr = 1; lr <= lowreg; lr++) {
1597 0 : if (nOffspring(lr) == 1) {
1598 0 : casacore::IPosition pos(itsDim,0);
1599 0 : decrement(pos);
1600 0 : while (increment(pos,shape())) {
1601 0 : if (contourMap.getCell(pos) == lr) setCell(pos, cgindex);
1602 : }
1603 0 : cgindex++;
1604 0 : }
1605 : } //IMPR: probably can make this work with single scan
1606 : //similar to above algorithm
1607 :
1608 : // Finally, scan regions that only exist in lower contour. Same as above,
1609 : // but since these are new regions, add their initial positions to the seed
1610 : // arrays and increment the region count.
1611 :
1612 0 : for (casacore::Int lr = 1; lr <= lowreg; lr++) {
1613 0 : if (nOffspring(lr) == 0) {
1614 :
1615 0 : casacore::IPosition newregioncenter(itsDim,0);
1616 0 : casacore::uInt topcells = 0;
1617 : {
1618 0 : casacore::IPosition pos(itsDim,0);
1619 0 : decrement(pos);
1620 0 : while (increment(pos,shape())) {
1621 : //cout << pos << endl;
1622 0 : if (contourMap.getCell(pos) == lr) {
1623 0 : setCell(pos, cgindex);
1624 0 : newregioncenter += pos;
1625 0 : topcells++;
1626 : }
1627 : }
1628 0 : }
1629 0 : newregioncenter /= topcells; //note: integer division. may or may not
1630 : //want to keep this
1631 :
1632 0 : cgindex++;
1633 :
1634 0 : if ((itsNRegions % blocksize) == 0) {
1635 0 : regcenter.resize(itsNRegions+blocksize, true);
1636 0 : originlevel.resize(itsNRegions+blocksize, true);
1637 : }
1638 :
1639 : // Add to region center array
1640 0 : regcenter[itsNRegions] = newregioncenter;
1641 0 : originlevel(itsNRegions) = c;
1642 0 : itsNRegions++;
1643 0 : }
1644 : }
1645 : }
1646 :
1647 :
1648 : // At end of scan, assign all flagged pixels to region containing the
1649 : // nearest "seed" - the first point identified in each region.
1650 :
1651 : if (printIntermediates == 2) {
1652 : cout << "Located the following seeds:" << endl;
1653 : for (casacore::uInt s = 0; s < itsNRegions; s++)
1654 : cout << s << " at " << regcenter[s]
1655 : << " in component #" << getCell(regcenter[s]) << endl;
1656 : }
1657 :
1658 : {
1659 0 : casacore::IPosition pos(itsDim,0);
1660 0 : decrement(pos);
1661 0 : while (increment(pos,shape())) {
1662 0 : if (getCell(pos) == INDETERMINATE) {
1663 0 : casacore::Int mindistsq = 1073741823; //maximum casacore::Int value
1664 0 : for (casacore::uInt s = 0; s < itsNRegions; s++) {
1665 0 : casacore::Int distsq = 0;
1666 0 : if (originlevel(s) == -1) continue; //defunct region
1667 0 : for (casacore::uInt a = 0; a < itsDim; a++) {
1668 0 : distsq += (pos(a) - regcenter[s](a)) * (pos(a) - regcenter[s](a));
1669 : }
1670 0 : if (distsq < mindistsq) {
1671 0 : setCell(pos, getCell(regcenter[s]) );
1672 0 : mindistsq = distsq;
1673 : }
1674 : }
1675 : }
1676 : }
1677 0 : }
1678 :
1679 0 : if (minRange > 1) renumberRegions();
1680 :
1681 0 : return;
1682 0 : }
1683 :
1684 :
1685 :
1686 : template <class T>
1687 0 : void ImageDecomposer<T>::decomposeImage()
1688 : {
1689 0 : if (!itsDeblendIt)
1690 : {
1691 : // Find contiguous regions via thresholding
1692 :
1693 0 : casacore::uInt nRegions = identifyRegions(itsThresholdVal,itsNAxis);
1694 0 : cout << "Found " << nRegions << " regions" << endl;
1695 :
1696 : // Fit each region. A further pass is done through each region
1697 : // to ascertain whether there are multiple components to be
1698 : // fit within it.
1699 :
1700 0 : if (itsFitIt) fitRegions();
1701 :
1702 : }
1703 : else
1704 : {
1705 0 : const casacore::Bool showProcess = false;
1706 0 : casacore::Bool varyContours = false; //this is always false now...
1707 :
1708 : // Make a local decomposer
1709 :
1710 0 : ImageDecomposer<T> thresholdMap(*itsImagePtr);
1711 :
1712 :
1713 : // Generate global contours
1714 :
1715 0 : casacore::Vector<T> mainContours(itsNContour);
1716 0 : if (!varyContours) {
1717 0 : mainContours = autoContour(itsNContour, itsThresholdVal);
1718 : //cerr << "Main contours = " << mainContours << endl;
1719 : if (showProcess) displayContourMap(mainContours);
1720 : }
1721 :
1722 : // Find contiguous regions via thresholding
1723 :
1724 0 : casacore::uInt nRegions = thresholdMap.identifyRegions(itsThresholdVal, itsNAxis);
1725 0 : casacore::uInt nBadRegions = 0;
1726 0 : if (itsMinRange > 1)
1727 : {
1728 : // Eliminate weak regions
1729 0 : casacore::Vector<T> maxvals;
1730 0 : maxvals = thresholdMap.findAllRegionGlobalMax();
1731 0 : casacore::Vector<casacore::Bool> killRegion(nRegions,0);
1732 0 : for (casacore::uInt r = 0; r < nRegions; r++) {
1733 0 : if (thresholdMap.getContourVal(maxvals(r),mainContours)+1 <itsMinRange)
1734 : {
1735 0 : killRegion(r) = 1;
1736 0 : nBadRegions++;
1737 : }
1738 : }
1739 0 : thresholdMap.destroyRegions(killRegion);
1740 0 : }
1741 :
1742 0 : nRegions -= nBadRegions;
1743 :
1744 : if (showProcess) {
1745 : cout << "Located " << nRegions << " regions above threshold "
1746 : << itsThresholdVal << "." << endl;
1747 : thresholdMap.display();
1748 : }
1749 :
1750 :
1751 : // Find a blc and a trc for each region
1752 :
1753 0 : casacore::Block<casacore::IPosition> blc(nRegions);
1754 0 : casacore::Block<casacore::IPosition> trc(nRegions);
1755 0 : thresholdMap.boundRegions(blc, trc);
1756 0 : if (isDerived()) zero();
1757 :
1758 : if (showProcess) {
1759 : cout << "Bounded " << nRegions<<" regions for decomposition and fitting:"
1760 : << endl;
1761 : for (casacore::uInt r = 0; r < nRegions; r++) {
1762 : cout << r+1 <<": " << blc[r] << trc[r] << endl;
1763 : }
1764 : }
1765 :
1766 : // For each distinct region above the threshold, form a componentmap
1767 : // (subcomponentmap) and perform the fitting. Regions are treated as
1768 : // independent entities by the fitter - even if one region contains a
1769 : // very high-sigma component that may extend into another region, this
1770 : // is not taken into account by the other region
1771 :
1772 0 : for (casacore::uInt r=0; r<nRegions; r++) {
1773 :
1774 : // Make a decomposer for this region
1775 :
1776 0 : casacore::Slicer sl(blc[r], trc[r]-blc[r], casacore::Slicer::endIsLength);
1777 0 : casacore::SubImage<T> subIm(*itsImagePtr, sl);
1778 0 : ImageDecomposer<T> subpmap(subIm);
1779 0 : subpmap.copyOptions(*this);
1780 :
1781 : // Flag pixels outside the target region (this makes sure that other
1782 : // regions that happen to overlap part of the target region's bounding
1783 : // rectangle are not counted twice, and that only the target region
1784 : // pixels are used in fitting.)
1785 : {
1786 0 : casacore::IPosition pos(subpmap.itsDim,0); decrement(pos);
1787 0 : while (increment(pos,subpmap.shape())) {
1788 0 : if (thresholdMap.getCell(blc[r] + pos) != casacore::Int(r+1)) {
1789 0 : subpmap.setCell(pos, MASKED);
1790 : }
1791 : }
1792 0 : }
1793 :
1794 0 : casacore::Vector<T> subContours(itsNContour);
1795 : casacore::Vector<T> *contourPtr;
1796 :
1797 : // Generate contours for this region or use global
1798 : // ones for entire image
1799 :
1800 0 : if (varyContours) {
1801 0 : subContours = subpmap.autoContour(itsNContour, itsThresholdVal);
1802 0 : contourPtr = &subContours;
1803 : } else {
1804 0 : contourPtr = &mainContours;
1805 : }
1806 :
1807 : if (showProcess) {
1808 : cout << "-----------------------------------------" << endl;
1809 : cout << "Subimage " << r << endl;
1810 : cout << "Contour Map:" << endl;
1811 : subpmap.displayContourMap(*contourPtr);
1812 : }
1813 :
1814 : // Deblend components in this region
1815 :
1816 0 : subpmap.deblendRegions(*contourPtr, itsMinRange, itsNAxis);
1817 : if (showProcess) {
1818 : cout << "Component Map:" << endl;
1819 : subpmap.display();
1820 : }
1821 :
1822 0 : if (itsFitIt) {
1823 : // Fit gaussians to region
1824 0 : subpmap.fitComponents();
1825 : }
1826 : else {
1827 : // Just estimate
1828 0 : subpmap.itsNComponents = subpmap.itsNRegions;
1829 0 : subpmap.itsList.resize();
1830 0 : subpmap.itsList = subpmap.estimateComponents();
1831 : }
1832 :
1833 : if (showProcess) {
1834 : cout << "Object " << r+1 << " subcomponents: " << endl;
1835 : subpmap.printComponents();
1836 : cout << endl;
1837 : }
1838 :
1839 : // Add this region back into the main component map
1840 :
1841 0 : synthesize(subpmap, blc[r]);
1842 : }
1843 0 : }
1844 0 : return;
1845 : }
1846 :
1847 :
1848 :
1849 : // Fitting functions
1850 : // -----------------
1851 :
1852 : template <class T>
1853 0 : casacore::Matrix<T> ImageDecomposer<T>::fitRegion(casacore::Int nregion)
1854 : {
1855 0 : cout << "Fit Region " << nregion << endl;
1856 :
1857 : // Fits multiple gaussians to a single region. First performs a local
1858 : // maximum scan to estimate the number of components in the region.
1859 :
1860 0 : casacore::uInt nGaussians = 0;
1861 0 : casacore::uInt npoints = 0;
1862 0 : casacore::uInt ngpar = 0;
1863 0 : if (itsDim == 2) ngpar = 6;
1864 0 : if (itsDim == 3) ngpar = 9;
1865 0 : if (!isDerived()) nregion = 0; //fit to all data.
1866 :
1867 : // Determine number of data points in the region
1868 :
1869 : {
1870 0 : casacore::IPosition pos(itsDim,0);
1871 0 : decrement(pos);
1872 0 : while (increment(pos,shape())) {
1873 0 : if (getCell(pos) == nregion) npoints++;
1874 : }
1875 0 : }
1876 :
1877 : // Fill data and positions arrays
1878 :
1879 0 : casacore::Matrix<T> positions(npoints,itsDim);
1880 0 : casacore::Vector<T> dataValues(npoints);
1881 0 : casacore::Vector<T> sigma(npoints);
1882 0 : sigma = 1.0;
1883 0 : casacore::uInt k = 0;
1884 : {
1885 0 : casacore::IPosition pos(itsDim,0);
1886 0 : decrement(pos);
1887 0 : while (increment(pos,shape())) {
1888 0 : if (getCell(pos) == nregion) {
1889 0 : for (casacore::uInt i = 0; i<itsDim; i++) {
1890 0 : positions(k,i) = T(pos(i));
1891 : }
1892 0 : dataValues(k) = getImageVal(pos);
1893 0 : k++;
1894 : }
1895 : }
1896 0 : }
1897 :
1898 : // Estimate the initial parameters.
1899 :
1900 0 : casacore::Matrix<T> width;
1901 0 : casacore::Vector<T> maxval;
1902 0 : casacore::Block<casacore::IPosition> maxvalpos;
1903 :
1904 : // This estimates whether there are multiple components
1905 : // in the current region or not.
1906 :
1907 0 : findRegionLocalMax(maxval, maxvalpos, nregion, 2);
1908 0 : estimateComponentWidths(width, maxvalpos);
1909 0 : nGaussians = maxval.nelements();
1910 0 : cout << "Found " << nGaussians << " components" << endl;
1911 :
1912 0 : casacore::Matrix<T> initestimate(nGaussians, ngpar);
1913 0 : casacore::Matrix<T> solution(nGaussians, ngpar);
1914 :
1915 0 : if (itsDim == 2) {
1916 0 : for (casacore::uInt r = 0; r < nGaussians; r++) {
1917 0 : initestimate(r,0) = maxval(r);
1918 0 : initestimate(r,1) = maxvalpos[r](0);
1919 0 : initestimate(r,2) = maxvalpos[r](1);
1920 0 : initestimate(r,3) = width(r,1);
1921 0 : initestimate(r,4) = width(r,0)/width(r,1);
1922 0 : initestimate(r,5) = 0;
1923 : }
1924 : }
1925 0 : if (itsDim == 3) {
1926 0 : for (casacore::uInt r = 0; r < nGaussians; r++) {
1927 0 : initestimate(r,0) = maxval(r);
1928 0 : initestimate(r,1) = maxvalpos[r](0);
1929 0 : initestimate(r,2) = maxvalpos[r](1);
1930 0 : initestimate(r,3) = maxvalpos[r](2);
1931 0 : initestimate(r,4) = width(r,0);
1932 0 : initestimate(r,5) = width(r,1);
1933 0 : initestimate(r,6) = width(r,2);
1934 0 : initestimate(r,7) = (0.0);
1935 0 : initestimate(r,8) = (0.0);
1936 : }
1937 : }
1938 :
1939 : // Fit for nGaussians simultaneously
1940 :
1941 0 : solution = fitGauss(positions, dataValues, initestimate);
1942 0 : return solution;
1943 :
1944 0 : }
1945 :
1946 : template <class T>
1947 0 : void ImageDecomposer<T>::fitRegions()
1948 : {
1949 : // Fits gaussians to an image; multiple gaussians per region in the pmap.
1950 : // The regions are fit sequentially and independently, so this function
1951 : // can be used on the main image.
1952 : // If the map is not yet thresholded, will fit to the entire image as if it
1953 : // were a single composite object, which will be very slow.
1954 :
1955 0 : casacore::uInt ngpar = 0;
1956 0 : if (itsDim == 2) ngpar = 6;
1957 0 : if (itsDim == 3) ngpar = 9;
1958 :
1959 0 : if (itsNRegions == 0) { //not deblended.
1960 0 : itsList = fitRegion(0);
1961 0 : return;
1962 : }
1963 : //
1964 0 : for (casacore::uInt r = 1; r <= itsNRegions; r++) {
1965 0 : casacore::Matrix<T> subitsList;
1966 0 : casacore::Matrix<T> olditsList;
1967 0 : subitsList = fitRegion(r);
1968 0 : olditsList = itsList;
1969 0 : itsList.resize(itsNComponents + subitsList.nrow(), ngpar);
1970 : //
1971 0 : for (casacore::uInt c = 0; c < itsNComponents; c++) {
1972 0 : for (casacore::uInt p = 0; p < ngpar; p++) {
1973 0 : itsList(c,p) = olditsList(c,p);
1974 : }
1975 : }
1976 :
1977 0 : for (casacore::uInt subc = 0; subc < subitsList.nrow(); subc++) {
1978 0 : for (casacore::uInt p = 0; p < ngpar; p++) {
1979 0 : itsList(itsNComponents+subc, p) = subitsList(subc, p);
1980 : }
1981 : }
1982 0 : itsNComponents += subitsList.nrow();
1983 : }
1984 :
1985 0 : return;
1986 : }
1987 :
1988 :
1989 : template <class T>
1990 0 : void ImageDecomposer<T>::fitComponents()
1991 : {
1992 : // Fits gaussians to an image; one gaussian per region in the pmap.
1993 : // This function is intended to be used only by ImageDecomposer on its
1994 : // intermediary subimages; using it at higher level will execute a full
1995 : // gaussian fit on the main image and will be extremely slow. Every
1996 : // nonflagged object pixel in the image is used in fitting.
1997 :
1998 : // If the deblended flag is true, the function will treat each region as
1999 : // an individual component and will fit that many gaussians to the image
2000 :
2001 0 : casacore::uInt ngpar = itsDim * 3;
2002 0 : casacore::uInt npoints = 0;
2003 :
2004 0 : if (!isDerived()) {
2005 0 : throw(casacore::AipsError("Cannot fit until components are deblended"
2006 : " - use identifyRegions() or deblendRegions()"));
2007 : }
2008 :
2009 :
2010 : // Determine number of data points in all the regions
2011 : // and get data and position vectors
2012 :
2013 : {
2014 0 : casacore::IPosition pos(itsDim,0);
2015 0 : decrement(pos);
2016 0 : while (increment(pos,shape())) {
2017 0 : if (getCell(pos) > 0) npoints++;
2018 : }
2019 0 : }
2020 :
2021 0 : casacore::Matrix<T> positions(npoints,itsDim);
2022 0 : casacore::Vector<T> dataValues(npoints);
2023 :
2024 : {
2025 0 : casacore::IPosition pos(itsDim,0);
2026 0 : decrement(pos);
2027 0 : casacore::uInt p = 0;
2028 0 : while (increment(pos,shape())) {
2029 0 : if (getCell(pos) > 0) {
2030 0 : for (casacore::uInt i=0; i<itsDim; i++) {
2031 0 : positions(p,i) = T(pos(i));
2032 : }
2033 0 : dataValues(p) = getImageVal(pos);
2034 0 : p++;
2035 : }
2036 : }
2037 0 : }
2038 :
2039 : // Estimate the initial parameters.
2040 :
2041 0 : casacore::Matrix<T> initestimate(itsNRegions, ngpar);
2042 0 : casacore::Matrix<T> solution(itsNRegions, ngpar);
2043 :
2044 0 : initestimate = estimateComponents();
2045 :
2046 0 : solution = fitGauss(positions, dataValues, initestimate);
2047 :
2048 0 : itsNComponents = itsNRegions;
2049 0 : itsList.resize(solution.shape());
2050 0 : itsList = solution;
2051 :
2052 0 : return;
2053 0 : }
2054 :
2055 :
2056 : template <class T>
2057 0 : casacore::Matrix<T> ImageDecomposer<T>::estimateComponents()
2058 : {
2059 0 : casacore::uInt ngaussians = itsNRegions;
2060 0 : casacore::uInt ngpar = 0;
2061 0 : if (itsDim == 2) ngpar = 6;
2062 0 : if (itsDim == 3) ngpar = 9;
2063 0 : if (!isDerived()) {
2064 0 : throw(casacore::AipsError("Cannot estimate until components are deblended"
2065 : " - use identifyRegions() or deblendRegions()"));
2066 : }
2067 :
2068 :
2069 0 : casacore::Matrix<T> estimate(ngaussians, ngpar);
2070 0 : casacore::Matrix<T> width;
2071 0 : casacore::Vector<T> maxval;
2072 0 : casacore::Block<casacore::IPosition> maxvalpos;
2073 :
2074 0 : ngaussians = itsNRegions;
2075 0 : findAllRegionGlobalMax(maxval, maxvalpos);
2076 :
2077 : // This is based on the moment analysis methods given in Jarvis & Tyson 1981,
2078 : // though they have been generalized to 3D. The formula to estimate phi
2079 : // (3D parameter 8) was not derived rigorously and may not be correct, though
2080 : // it works very well overall.
2081 :
2082 0 : for (casacore::uInt r = 0; r < ngaussians; r++)
2083 : {
2084 0 : if (itsDim == 2) {
2085 0 : casacore::Matrix<T> M;
2086 0 : M = calculateMoments(r+1);
2087 0 : estimate(r,0) = maxval[r];
2088 0 : estimate(r,1) = M(1,0) / M(0,0);
2089 0 : estimate(r,2) = M(0,1) / M(0,0);
2090 0 : estimate(r,3) = 2.84 * sqrt(M(0,2)/M(0,0));
2091 0 : estimate(r,4) = sqrt(M(2,0)/M(0,2));
2092 0 : estimate(r,5) = 0.5 * atan(2 * M(1,1) / (M(2,0) - M(0,2)));
2093 0 : if (estimate(r,3) < 1.0) estimate(r,3) = 1.0;
2094 0 : if (estimate(r,4)*estimate(r,3) < 1.0) estimate(r,4) = 1.0/estimate(r,3);
2095 0 : if (casacore::isNaN(estimate(r,4))) estimate(r,4) = 1.0/estimate(r,3);
2096 0 : if (casacore::isNaN(estimate(r,5))) estimate(r,5) = 0;
2097 0 : } else if (itsDim == 3) {
2098 0 : casacore::Cube<T> M;
2099 0 : M = calculateMoments(r+1);
2100 0 : estimate(r,0) = maxval[r];
2101 0 : estimate(r,1) = M(1,0,0) / M(0,0,0);
2102 0 : estimate(r,2) = M(0,1,0) / M(0,0,0);
2103 0 : estimate(r,3) = M(0,0,1) / M(0,0,0);
2104 0 : estimate(r,4) = 2.84 * sqrt(M(2,0,0) / M(0,0,0));
2105 0 : estimate(r,5) = 2.84 * sqrt(M(0,2,0) / M(0,0,0));
2106 0 : estimate(r,6) = 2.84 * sqrt(M(0,0,2) / M(0,0,0));
2107 0 : estimate(r,7) = 0.5 * atan(2 * M(1,1,0) / (M(2,0,0) - M(0,2,0)));
2108 0 : estimate(r,8) = -0.5 * atan(2 * M(1,0,1) /
2109 0 : ((M(2,0,0) - M(0,0,2))*cos(estimate(r,7)) +
2110 0 : (M(0,2,0) - M(0,0,2))*sin(estimate(r,7))));
2111 0 : if (estimate(r,4) < 1.0) estimate(r,4) = 1.0;
2112 0 : if (estimate(r,5) < 1.0) estimate(r,5) = 1.0;
2113 0 : if (estimate(r,6) < 1.0) estimate(r,6) = 1.0;
2114 0 : if (casacore::isNaN(estimate(r,8))) estimate(r,8) = 0;
2115 0 : }
2116 : }
2117 :
2118 0 : return estimate;
2119 0 : }
2120 :
2121 :
2122 :
2123 :
2124 :
2125 :
2126 :
2127 : template <class T>
2128 0 : casacore::Matrix<T> ImageDecomposer<T>::fitGauss(const casacore::Matrix<T>& positions,
2129 : const casacore::Vector<T>& dataValues,
2130 : const casacore::Matrix<T>& initestimate) const
2131 : {
2132 : // Fits the specified number of 3D gaussians to the data, and returns
2133 : // solution in image (world) coordinates.
2134 :
2135 : //casacore::uInt ngpar = 0;
2136 0 : casacore::uInt ngaussians = initestimate.nrow();
2137 : //if (itsDim == 2) ngpar = 6;
2138 : //if (itsDim == 3) ngpar = 9;
2139 :
2140 0 : casacore::Matrix<T> solution;
2141 : //T chisquare;
2142 :
2143 : // Might be useful to send to screen in AIPS++
2144 : //cout << "Primary estimation matrix:" << endl;
2145 : //for (casacore::uInt r = 0; r < ngaussians; r++)
2146 : // cout << initestimate.row(r) << endl;
2147 :
2148 0 : casacore::FitGaussian<T> fitter(itsDim,ngaussians);
2149 0 : fitter.setFirstEstimate(initestimate);
2150 0 : if (itsMaxRetries < 0) {
2151 0 : fitter.setMaxRetries(itsDim * ngaussians);
2152 : }
2153 : else {
2154 0 : fitter.setMaxRetries(itsMaxRetries);
2155 : }
2156 :
2157 : try{
2158 0 : solution = fitter.fit(positions, dataValues, itsMaximumRMS, itsMaxIter,
2159 0 : itsConvCriteria);
2160 0 : } catch (casacore::AipsError fiterr) {
2161 0 : cout << fiterr.getMesg() << endl;
2162 0 : cout << "Fitting failed." << endl;
2163 0 : solution = 0;
2164 : //chisquare = -1.0;
2165 0 : return solution;
2166 : }
2167 :
2168 0 : if (fitter.converged()) {
2169 : //chisquare = fitter.chisquared();
2170 : } else {
2171 0 : cout << "Fitting did not converge to a reasonable result - using estimate."
2172 0 : << endl;
2173 0 : solution = initestimate;
2174 : //chisquare = -1.0;
2175 0 : return solution;
2176 : }
2177 :
2178 0 : return solution;
2179 0 : }
2180 :
2181 :
2182 :
2183 :
2184 :
2185 : template <class T>
2186 : void ImageDecomposer<T>::display() const
2187 : {
2188 : // Displays the componentmap in a terminal environment as an array of
2189 : // characters on screen.
2190 :
2191 : casacore::Int windowwidth = 80;
2192 : casacore::Int const spacing = 4;
2193 : casacore::Int const cposinc = shape(0) * 2 + spacing;
2194 : if (cposinc > windowwidth) windowwidth = cposinc;
2195 : casacore::Int cpos = 0;
2196 : //
2197 : casacore::Int z = 0;
2198 : casacore::Int benchz = 0;
2199 : //
2200 : //cerr << "shape = " << shape() << endl;
2201 : while (z < shape(2)) {
2202 : for (casacore::Int y = 0; y < shape(1); y++) {
2203 : z = benchz;
2204 : while ((cpos += cposinc) < windowwidth && z < shape(2)) {
2205 : for (casacore::Int x = 0; x < itsShape(0); x++) {
2206 : if (getCell(x,y,z) >= 0) {
2207 : cout << getCell(x,y,z);
2208 : } else if (getCell(x,y,z) == INDETERMINATE) {
2209 : cout << '*';
2210 : } else if (getCell(x,y,z) == MASKED) {
2211 : cout << '-';
2212 : }
2213 : if (getCell(x,y,z) < 10) {
2214 : cout << ' ';
2215 : }
2216 : }
2217 : z++;
2218 : cout << " ";
2219 : }
2220 : cpos = 0;
2221 : cout << endl;
2222 : }
2223 : benchz = z;
2224 : cout << endl;
2225 : }
2226 : return;
2227 : }
2228 :
2229 :
2230 : // Console display functions
2231 : // -------------------------
2232 :
2233 :
2234 : template <class T>
2235 : void ImageDecomposer<T>::displayContourMap(const casacore::Vector<T>& clevels) const
2236 : {
2237 : // Displays the target image as a contourmap in a terminal environment as
2238 : // an array of characters on screen.
2239 :
2240 : casacore::Int windowwidth = 80;
2241 : casacore::Int const spacing = 4;
2242 : casacore::Int const cposinc = shape(0) * 2 + spacing;
2243 : if (cposinc > windowwidth) windowwidth = cposinc;
2244 : casacore::Int cpos = 0;
2245 :
2246 : casacore::Int z = 0;
2247 : casacore::Int benchz = 0;
2248 : cout << "Contour levels:" << clevels << endl;
2249 :
2250 : if (itsDim == 2) {
2251 : for (casacore::Int y = 0; y < shape(1); y++) {
2252 : for (casacore::Int x = 0; x < shape(0); x++) {
2253 : if (getContourVal(x,y,clevels) >= 0) {
2254 : cout << getContourVal(x,y,clevels);
2255 : }
2256 : else if (getContourVal(x,y,clevels) <= -1) {
2257 : cout << '-';
2258 : }
2259 : if (getContourVal(x,y,clevels) < 10) {
2260 : cout << ' ';
2261 : }
2262 : }
2263 : cout << endl;
2264 : }
2265 : cout << endl;
2266 : }
2267 :
2268 : if (itsDim == 3){
2269 : //this actually works in 2 dimensions on a casacore::TempImage, but not on a
2270 : //casacore::SubImage, where there is a failure inside the getImageVal command
2271 : //on a failed assertion involving a casacore::LatticeRegion object. As a result
2272 : //the above specialization was written, but it would be nice if 3-D
2273 : //IPositions worked on 2-D images in casacore::SubImage as well as TempImage.
2274 : while (z < shape(2)) {
2275 : for (casacore::Int y = 0; y < shape(1); y++) {
2276 : z = benchz;
2277 : while ((cpos += cposinc) < windowwidth && (z < shape(2))) {
2278 : for (casacore::Int x = 0; x < shape(0); x++) {
2279 : if (getContourVal(x,y,z,clevels) >= 0) {
2280 : cout << getContourVal(x,y,z,clevels);
2281 : }
2282 : else if (getContourVal(x,y,z,clevels) <= -1) {
2283 : cout << '-';
2284 : }
2285 : if (getContourVal(x,y,z,clevels) < 10) {
2286 : cout << ' ';
2287 : }
2288 : }
2289 : z++;
2290 : cout << " ";
2291 : }
2292 : cpos = 0;
2293 : cout << endl;
2294 : }
2295 : benchz = z;
2296 : cout << endl;
2297 : }
2298 : cout << endl;
2299 : }
2300 :
2301 : return;
2302 : }
2303 :
2304 :
2305 : template <class T>
2306 0 : void ImageDecomposer<T>::printComponents() const
2307 : {
2308 : //Prints the components as formatted output on screen.
2309 : //IMPR: Probably could be modified as an ostream output function.
2310 :
2311 0 : casacore::Matrix<T> clist;
2312 0 : clist = componentList();
2313 :
2314 0 : for (casacore::uInt g = 0; g < clist.nrow(); g++)
2315 : {
2316 0 : cout << g+1 << ": ";
2317 0 : if (itsList(g,0) == T(0)) {
2318 0 : cout << "Failed";
2319 : } else {
2320 0 : cout << "Peak: " << clist(g,0) << " ";
2321 :
2322 0 : if (itsDim == 2) {
2323 0 : cout << "Mu: [" << clist(g,1)
2324 0 : << ", " << clist(g,2) << "] ";
2325 0 : cout << "Axes: [" << clist(g,3)
2326 0 : << ", " << clist(g,3) * clist(g,4) << "] ";
2327 0 : cout << "Rotation: " << clist(g,5) /* * 180 / C::pi */;
2328 : }
2329 0 : if (itsDim == 3) {
2330 0 : cout << "Mu: [" << clist(g,1)
2331 0 : << ", " << clist(g,2)
2332 0 : << ", " << clist(g,3) << "] ";
2333 0 : cout << "Axes: [" << clist(g,4)
2334 0 : << ", " << clist(g,5)
2335 0 : << ", " << clist(g,6) << "] ";
2336 0 : cout << "Rotation: [" << clist(g,7)/* *180/C::pi */
2337 0 : << ", " << clist(g,8) /* *180/C::pi */ << "]";
2338 : }
2339 : }
2340 0 : cout << endl;
2341 : }
2342 :
2343 0 : return;
2344 0 : }
2345 :
2346 :
2347 : // Functions associated only with other classes
2348 : // --------------------------------------------
2349 :
2350 : template <class T>
2351 0 : void ImageDecomposer<T>::correctBlcTrc(casacore::IPosition& blc, casacore::IPosition& trc) const
2352 : {
2353 : //Ensures blc and trc correctly describe the limits of a rectangular block.
2354 :
2355 : casacore::Int t;
2356 0 : for (casacore::uInt i = 0; i<itsDim; i++) {
2357 0 : if (blc(i)<0) blc(i) = 0;
2358 0 : if (trc(i)>shape(i)) trc(i) = shape(i);
2359 0 : if (trc(i)<0) trc(i) = 0;
2360 : //
2361 0 : if (blc(i)>shape(i)) blc(i) = shape(i);
2362 0 : if (blc(i)>trc(i)) { // nebk - ERROR should be trc(a) not trc(0) ??
2363 0 : t = blc(i);
2364 0 : blc(i) = trc(i);
2365 0 : trc(i) = t;
2366 : }
2367 : }
2368 0 : return;
2369 : }
2370 :
2371 : template <class T>
2372 0 : inline casacore::Bool ImageDecomposer<T>::increment(casacore::IPosition& pos,
2373 : const casacore::IPosition& limit) const
2374 : {
2375 : // N-Dimensional looping function: use in place of nested for loops
2376 : // Returns false when pos reaches limit.
2377 : // Use as follows: while(increment(pos,limit))
2378 : // IMPR: this function probably should be global or in IPosition. Or even
2379 : // better, omitted completely by using LatticeIterators.
2380 :
2381 0 : pos(itsDim-1)++;
2382 0 : for (casacore::uInt i = itsDim-1; i>0; i--) {
2383 0 : if (pos(i) == limit(i)) {
2384 0 : pos(i) = 0;
2385 0 : pos(i-1)++;
2386 : } else {
2387 0 : return true;
2388 : }
2389 : }
2390 : //
2391 0 : if (pos(0) == limit(0)) {
2392 0 : return false;
2393 : } else {
2394 0 : return true;
2395 : }
2396 : }
2397 :
2398 : template <class T>
2399 0 : inline void ImageDecomposer<T>::decrement(casacore::IPosition& pos) const
2400 : {
2401 : //To ensure while loop starts at 0,0,0..., decrement before first increment
2402 0 : pos(itsDim-1)--;
2403 0 : }
2404 :
2405 :
2406 :
2407 : /*
2408 : casacore::RO_LatticeIterator<casacore::Int> otherIter(*(other.itsMapPtr));
2409 : casacore::Bool deleteOther, deleteThis;
2410 : const casacore::Int* pOther = 0;
2411 : casacore::Int* pThis = 0;
2412 : for (otherIter.reset(); !otherIter.atEnd(); otherIter++) {
2413 : const casacore::Array<casacore::Int>& otherArray = otherIter.cursor();
2414 : casacore::Array<casacore::Int> thisArray = itsMapPtr->getSlice(otherIter.position(), otherIter.cursorShape());
2415 : //
2416 : pOther = otherArray.getStorage(deleteOther);
2417 : pThis = thisArray.getStorage(deleteThis);
2418 : //
2419 : for (casacore::uInt i=0; i<otherIter.cursor().nelements(); i++) {
2420 : if (pOther[i] != regionID) pThis[i] = MASKED;
2421 : }
2422 : //
2423 : otherArray.freeStorage(pOther, deleteOther);
2424 : thisArray.putStorage(pThis, deleteThis);
2425 : }
2426 : */
2427 :
2428 :
2429 : } //# NAMESPACE CASA - END
2430 :
|